<!-- SPEC: PJ2026-010405 云端控制台 / Access. -->
<!-- Implementation reference: draft-2026-07-13-p0-cloud-console. -->
<!-- Responsibility: 以合法 grid/row/gridcell 语义呈现权限矩阵与授权清单。 -->

<script setup lang="ts">
import { List, TableProperties } from "lucide-vue-next";
import FactPath, { type FactPathStep } from "@/components/console/FactPath.vue";
import ViewModeSwitch from "@/components/console/ViewModeSwitch.vue";
import SectionFrame from "@/components/layout/SectionFrame.vue";
import { accessUserLabel, type AccessOpenFgaView, type AccessToolRow, type AccessUserRow } from "@/stores/admin-access-view";

defineProps<{
  rows: AccessUserRow[];
  tools: AccessToolRow[];
  selectedId: string | null;
  factSteps: FactPathStep[];
  openfga: AccessOpenFgaView;
  view: "matrix" | "list";
}>();

const emit = defineEmits<{
  select: [row: AccessUserRow];
  "update:view": [value: "matrix" | "list"];
}>();

function valueText(value: unknown): string {
  if (typeof value === "string" && value.trim()) return value;
  if (typeof value === "number") return String(value);
  if (typeof value === "boolean") return value ? "yes" : "no";
  return "-";
}
</script>

<template>
  <div class="operations-main-stack">
    <FactPath :steps="factSteps" label="授权事实路径" />
    <SectionFrame :title="view === 'matrix' ? '权限矩阵' : '授权清单'" description="同一授权 read model 的矩阵比较与紧凑清单。" :body-padding="false">
      <template #actions>
        <ViewModeSwitch :model-value="view" :options="[{ value: 'matrix', label: '矩阵', icon: TableProperties }, { value: 'list', label: '清单', icon: List }]" @update:model-value="emit('update:view', $event as 'matrix' | 'list')" />
      </template>
      <div v-if="view === 'matrix'" class="permission-matrix" role="grid" aria-label="用户权限矩阵" :aria-colcount="tools.length + 1" :style="{ '--permission-tool-count': tools.length }">
        <div class="permission-matrix-head" role="row">
          <span role="columnheader">用户</span>
          <span v-for="tool in tools" :key="tool.id" role="columnheader">{{ tool.label }}</span>
        </div>
        <div
          v-for="row in rows"
          :key="row.id"
          role="row"
          :aria-selected="row.id === selectedId"
          :data-selected="row.id === selectedId"
        >
          <span role="gridcell"><button type="button" @click="emit('select', row)"><strong>{{ accessUserLabel(row) }}</strong><small>{{ row.role }} · {{ row.status }}</small></button></span>
          <span v-for="tool in tools" :key="tool.id" role="gridcell" :data-allowed="row.tools[tool.id] ? 'true' : 'false'">{{ row.tools[tool.id] ? "允许" : "—" }}</span>
        </div>
      </div>
      <div v-else class="access-compact-list" role="list">
        <button v-for="row in rows" :key="row.id" type="button" role="listitem" :data-selected="row.id === selectedId" @click="emit('select', row)">
          <span><strong>{{ accessUserLabel(row) }}</strong><small>{{ row.username || row.id }}</small></span>
          <span class="status-pill" :data-status="row.status">{{ row.role }} / {{ row.status }}</span>
          <code>{{ row.toolCount }} tools</code><code>{{ row.tupleCount }} tuples</code>
        </button>
      </div>
    </SectionFrame>
    <details class="technical-disclosure">
      <summary>OpenFGA 技术详情</summary>
      <dl class="field-grid">
        <div><dt>mode</dt><dd>{{ valueText(openfga.mode) }}</dd></div>
        <div><dt>store</dt><dd>{{ valueText(openfga.storeName || openfga.storeId) }}</dd></div>
        <div><dt>model</dt><dd>{{ valueText(openfga.modelId) }}</dd></div>
        <div><dt>values</dt><dd>{{ openfga.valuesRedacted === false ? "visible" : "redacted" }}</dd></div>
      </dl>
    </details>
  </div>
</template>
