// =============================================================================
// WOOO AIOps - AwoooP M1 租戶管理頁面
// =============================================================================
// 顯示所有 tenant 清單，含 migration_mode badge 與 suspended 狀態

"use client";

import { useState, useEffect, useCallback } from "react";
import { useTranslations } from "next-intl";
import { Link } from "@/i18n/routing";
import {
  ArrowRight,
  Boxes,
  Building2,
  RefreshCw,
  AlertCircle,
  DollarSign,
  Ban,
  ChevronDown,
  CheckCircle2,
  GitBranch,
  Globe2,
  ListChecks,
  Lock,
  Network,
  ShieldCheck,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { getRuntimeApiBaseUrl } from "@/lib/runtime-api-base";

// =============================================================================
// Types
// =============================================================================

type MigrationMode =
  | "legacy_awoooi_default"
  | "shadow"
  | "canary"
  | "read_only"
  | "suggest"
  | "auto_remediate";

interface Tenant {
  project_id: string;
  display_name: string;
  migration_mode: MigrationMode;
  budget_limit_usd: number | string | null;
  is_active: boolean;
}

interface ApiResponse {
  tenants?: Tenant[];
  items?: Tenant[];
  total: number;
  asset_inventory?: TenantAssetInventory;
}

type TenantAssetSummary = {
  tenant_table_count: number;
  product_surface_count: number;
  public_route_count: number;
  public_gateway_snapshot_route_count: number;
  source_candidate_repo_count: number;
  source_in_scope_repo_count: number;
  source_primary_ready_count: number;
  owner_response_received_count: number;
  owner_response_accepted_count: number;
  runtime_gate_count: number;
  action_button_count: number;
};

type TenantProductSurface = {
  product_id: string;
  product_name: string;
  project_id: string;
  category: string;
  surface_kind: string;
  owner_lane: string;
  coverage_status: string;
  public_routes: string[];
  source_keys: string[];
  public_route_count: number;
  source_repo_count: number;
  missing_public_routes: string[];
  owner_response_received_count: number;
  owner_response_accepted_count: number;
  runtime_gate_count: number;
  action_button_count: number;
};

type TenantPublicRouteAsset = {
  domain: string;
  product_id: string;
  product_name: string;
  category: string;
  coverage_status: string;
  control_tier: string;
  upstream_count: number;
  admin_route_count: number;
  websocket_route_count: number;
  public_route_smoke_required: boolean;
  route_smoke_accepted: boolean;
  owner_response_accepted: boolean;
  runtime_gate_count: number;
  action_button_count: number;
  source: string;
};

type TenantSourceRepoAsset = {
  github_repo: string;
  source_key: string;
  source_scope_id: string;
  source_namespace_redacted: boolean;
  product_id: string;
  product_name: string;
  category: string;
  scope_status: string;
  readiness_state: string;
  risk: string;
  primary_ready: boolean;
  blocker_count: number;
  runtime_gate_count: number;
  action_button_count: number;
};

type TenantAssetInventory = {
  schema_version: string;
  mode: string;
  evidence_refs: string[];
  summary: TenantAssetSummary;
  products: TenantProductSurface[];
  public_routes: TenantPublicRouteAsset[];
  source_repos: TenantSourceRepoAsset[];
  boundaries: string[];
};

type GitHubTenantReadinessMetric = {
  key: string;
  value: string;
  icon: typeof ShieldCheck;
  tone: "neutral" | "warn";
};

type GitHubTenantReadinessScope = {
  key: string;
  name: string;
  status: string;
};

type OwnerResponseValidationTenantRef = {
  phase: string;
  key: string;
};

type AssetTone = "steady" | "warn" | "locked";

// =============================================================================
// 常數
// =============================================================================

const API_BASE = getRuntimeApiBaseUrl();

const githubTenantReadinessMetrics: GitHubTenantReadinessMetric[] = [
  { key: "candidateRepos", value: "10", icon: GitBranch, tone: "neutral" },
  { key: "inScopeRepos", value: "9", icon: ListChecks, tone: "warn" },
  { key: "ownerResponses", value: "0/24", icon: ShieldCheck, tone: "warn" },
  { key: "tenantScopeChanges", value: "0", icon: Lock, tone: "warn" },
];

const githubTenantReadinessScopes: GitHubTenantReadinessScope[] = [
  {
    key: "tenantSourceScope",
    name: "AWOOOI 第一租戶原始碼管控範圍",
    status: "等待中",
  },
  {
    key: "giteaInventoryOwner",
    name: "S4.9 Gitea 清冊負責人證明",
    status: "0/5",
  },
  {
    key: "githubTargetOwner",
    name: "S4.10 GitHub 目標負責人決策",
    status: "0/9",
  },
  {
    key: "workflowSecretOwner",
    name: "S4.12 工作流程 / 機密名稱負責人回覆",
    status: "0/5",
  },
];

const tenantScopeBoundaryItems = [
  "migrationLocked",
  "policyLocked",
  "runtimeLocked",
  "actionButtonsLocked",
];

const githubTenantReadinessBoundaries = [
  "sourceScopeWaiting",
  "ownerResponseWaiting",
  "repoCreationLocked",
  "refsMutationLocked",
  "githubPrimaryLocked",
  "giteaDisableLocked",
  "tenantPolicyLocked",
  "runtimeLocked",
  "actionButtonsLocked",
];

const ownerResponseValidationTenantRefs: OwnerResponseValidationTenantRef[] = [
  {
    phase: "S4.13",
    key: "validationRollup",
  },
  {
    phase: "S4.9",
    key: "giteaAttestation",
  },
  {
    phase: "S4.10",
    key: "githubTarget",
  },
  {
    phase: "S4.11",
    key: "refsTruth",
  },
  {
    phase: "S4.12",
    key: "workflowSecret",
  },
];

const ownerResponseValidationTenantBoundaries = [
  "responseNotReceived",
  "responseNotAccepted",
  "responseNotRejected",
  "tenantScopeWaiting",
  "tenantPolicyLocked",
  "repoCreationLocked",
  "refsSyncLocked",
  "workflowLocked",
  "secretValueBlocked",
  "githubPrimaryLocked",
  "runtimeLocked",
  "actionButtonsLocked",
];

const globalAssetBoundaryItems = [
  "readOnly",
  "redactedIdentity",
  "noRawRepository",
  "ownerResponseZero",
  "runtimeGateZero",
  "noActionButtons",
  "noRepoCreation",
  "noRouteChange",
  "noDeployment",
];

const ASSET_STATUS_TONES: Record<string, AssetTone> = {
  verified: "steady",
  read_only_visible: "steady",
  read_only_candidate: "warn",
  read_only_pending_smoke: "warn",
  owner_response_required: "warn",
};

const ASSET_CATEGORY_KEYS: Record<string, string> = {
  core_platform: "corePlatform",
  business_product: "businessProduct",
  public_site: "publicSite",
  platform_tool: "platformTool",
  public_route: "publicRoute",
  source_repo: "sourceRepo",
};

const ASSET_STATUS_KEYS: Record<string, string> = {
  verified: "verified",
  read_only_visible: "readOnlyVisible",
  read_only_candidate: "readOnlyCandidate",
  read_only_pending_smoke: "readOnlyPendingSmoke",
  owner_response_required: "ownerResponseRequired",
};

function assetToneClass(tone: AssetTone) {
  if (tone === "steady") return "border-[#9bc7a4] bg-[#f0faf2] text-[#17602a]";
  if (tone === "locked") return "border-[#b7add8] bg-[#f8f6fc] text-[#5b4b91]";
  return "border-[#d9b36f] bg-[#fff7e8] text-[#8a5a08]";
}

function AssetStatusBadge({
  status,
  t,
}: {
  status: string;
  t: ReturnType<typeof useTranslations>;
}) {
  const tone = ASSET_STATUS_TONES[status] ?? "locked";
  const key = ASSET_STATUS_KEYS[status] ?? "unknown";
  return (
    <span className={cn("inline-flex border px-2 py-0.5 text-[11px] font-semibold", assetToneClass(tone))}>
      {t(`statuses.${key}` as never)}
    </span>
  );
}

function assetCategoryLabel(category: string, t: ReturnType<typeof useTranslations>) {
  const key = ASSET_CATEGORY_KEYS[category] ?? "unknown";
  return t(`categories.${key}` as never);
}

function assetStatusLabel(status: string, t: ReturnType<typeof useTranslations>) {
  const key = ASSET_STATUS_KEYS[status] ?? "unknown";
  return t(`statuses.${key}` as never);
}

function countBy<T>(items: T[], selectKey: (item: T) => string) {
  return items.reduce<Record<string, number>>((counts, item) => {
    const key = selectKey(item);
    counts[key] = (counts[key] ?? 0) + 1;
    return counts;
  }, {});
}

function sourceRiskKey(risk: string) {
  const normalized = risk.toLowerCase();
  if (normalized === "high" || normalized === "medium" || normalized === "low") return normalized;
  return "unknown";
}

function sourceReadinessKey(readiness: string) {
  const normalized = readiness.toLowerCase();
  if (normalized === "need_refs_evidence" || (normalized.includes("refs") && normalized.includes("parity"))) {
    return "refsParity";
  }
  if (normalized === "need_target_decision" || (normalized.includes("target") && normalized.includes("decision"))) {
    return "targetDecision";
  }
  if (
    normalized === "need_internal_remote_decision" ||
    normalized.includes("internal_remote") ||
    (normalized.includes("remote") && normalized.includes("decision"))
  ) {
    return "internalRemoteDecision";
  }
  if (normalized === "need_scope_review" || (normalized.includes("scope") && normalized.includes("review"))) {
    return "scopeReview";
  }
  return "unknown";
}

function sourceRiskLabel(risk: string, t: ReturnType<typeof useTranslations>) {
  return t(`sourceRisk.${sourceRiskKey(risk)}` as never);
}

function sourceReadinessLabel(readiness: string, t: ReturnType<typeof useTranslations>) {
  const key = sourceReadinessKey(readiness);
  return t(`sourceReadiness.${key}` as never);
}

function sourceActionLabel(readiness: string, t: ReturnType<typeof useTranslations>) {
  const key = sourceReadinessKey(readiness);
  return t(`sourceActions.${key}` as never);
}

function sourcePublicScopeCode(index: number) {
  return `SRC-${String(index + 1).padStart(3, "0")}`;
}

function assetPublicCode(index: number) {
  return `AST-${String(index + 1).padStart(3, "0")}`;
}

function routePublicCode(index: number) {
  return `RTE-${String(index + 1).padStart(3, "0")}`;
}

function tenantPublicCode(index: number) {
  return `TNT-${String(index + 1).padStart(3, "0")}`;
}

const TENANT_PUBLIC_NAMES: Record<string, string> = {
  "awoooi": "核心營運租戶",
  "awooooi": "核心營運租戶",
  ewoooc: "行動商務租戶",
};

const PUBLIC_PRODUCT_NAMES: Record<string, string> = {
  "agent-bounty-protocol": "代理獎勵協議",
  "awoooi": "核心營運平台",
  "awooooi": "核心營運平台",
  bitan: "藥局服務前台",
  "bitan-pharmacy": "藥局服務平台",
  "clawbot-v5": "自動化助理平台",
  "ewoooc": "行動商務平台",
  "mo": "行動商務前台",
  "open-design": "設計系統",
  "source-control": "版本控管範圍",
  "tsenyang-website": "品牌網站",
  vibework: "工作協作產品",
  "wooo-aiops": "AI 維運平台",
  "wooo-infra-config": "基礎設施設定",
};

const RAW_REPOSITORY_IDENTIFIER_RE = /\b[a-z0-9][a-z0-9-]{1,}\/[A-Za-z0-9._-]+\b/;
const CJK_TEXT_RE = /[\u3400-\u9fff]/;

function isPublicAssetTextSafe(value: string | null | undefined) {
  const text = String(value ?? "").trim();
  if (!text) return false;
  if (RAW_REPOSITORY_IDENTIFIER_RE.test(text)) return false;
  return CJK_TEXT_RE.test(text);
}

function lookupPublicProductName(values: Array<string | null | undefined>, fallback: string) {
  for (const value of values) {
    const normalized = String(value ?? "").trim().toLowerCase();
    if (!normalized) continue;
    const candidates = [normalized, normalized.split("/").pop() ?? normalized];
    for (const candidate of candidates) {
      const mapped = PUBLIC_PRODUCT_NAMES[candidate];
      if (mapped) return mapped;
    }
  }
  return fallback;
}

function publicChineseAssetText(value: string | null | undefined, fallback: string) {
  const text = String(value ?? "").trim();
  return isPublicAssetTextSafe(text) ? text : fallback;
}

function tenantPublicName(tenant: Tenant, index: number) {
  return TENANT_PUBLIC_NAMES[tenant.project_id] ?? `租戶 ${tenantPublicCode(index)}`;
}

function tenantBudgetState(tenant: Tenant) {
  return tenant.budget_limit_usd == null ? "未設定" : "已設定";
}

function assetPublicProductName(item: TenantProductSurface, index: number) {
  const fallback = assetPublicCode(index);
  const mapped = lookupPublicProductName([item.product_id, item.project_id, item.product_name], fallback);
  return mapped === fallback ? publicChineseAssetText(item.product_name, fallback) : mapped;
}

function routePublicProductName(route: TenantPublicRouteAsset, index: number) {
  const fallback = routePublicCode(index);
  const mapped = lookupPublicProductName([route.product_id, route.product_name], fallback);
  return mapped === fallback ? publicChineseAssetText(route.product_name, fallback) : mapped;
}

function sourcePublicProductName(repo: TenantSourceRepoAsset, index: number) {
  const fallback = sourcePublicScopeCode(index);
  const mapped = lookupPublicProductName(
    [repo.product_id, repo.source_key, repo.github_repo, repo.product_name],
    fallback
  );
  if (mapped !== fallback) return mapped;
  if (
    repo.product_name === repo.github_repo ||
    repo.product_name === repo.source_key ||
    repo.product_name === repo.source_scope_id
  ) {
    return fallback;
  }
  return publicChineseAssetText(repo.product_name, fallback);
}

function sourceRiskClass(risk: string) {
  const key = sourceRiskKey(risk);
  if (key === "high") return "border-[#e2a29b] bg-[#fff0ef] text-[#9f2f25]";
  if (key === "medium") return "border-[#d9b36f] bg-[#fff7e8] text-[#8a5a08]";
  if (key === "low") return "border-[#9bc7a4] bg-[#f0faf2] text-[#17602a]";
  return "border-[#d8d3c7] bg-[#faf9f3] text-[#5f5b52]";
}

const MIGRATION_MODE_CONFIG: Record<
  MigrationMode,
  { label: string; bg: string; text: string; border: string }
> = {
  legacy_awoooi_default: {
    label: "舊版",
    bg: "bg-white",
    text: "text-[#5f5b52]",
    border: "border-[#d8d3c7]",
  },
  shadow: {
    label: "影子",
    bg: "bg-[#f4f1e8]",
    text: "text-[#5f5b52]",
    border: "border-[#d8d3c7]",
  },
  canary: {
    label: "金絲雀",
    bg: "bg-[#fff7e8]",
    text: "text-[#8a5a08]",
    border: "border-[#d9b36f]",
  },
  read_only: {
    label: "只讀",
    bg: "bg-[#eef5ff]",
    text: "text-[#1f5b9b]",
    border: "border-[#9bb6d9]",
  },
  suggest: {
    label: "建議",
    bg: "bg-[#f6f0ff]",
    text: "text-[#6541a5]",
    border: "border-[#baa7de]",
  },
  auto_remediate: {
    label: "自動修復",
    bg: "bg-[#f0faf2]",
    text: "text-[#17602a]",
    border: "border-[#9bc7a4]",
  },
};

// =============================================================================
// Sub Components
// =============================================================================

function MigrationModeBadge({ mode }: { mode: MigrationMode }) {
  const config = MIGRATION_MODE_CONFIG[mode] ?? MIGRATION_MODE_CONFIG.shadow;
  return (
    <span
      className={cn(
        "inline-flex items-center px-2.5 py-0.5 rounded-md text-xs font-mono font-medium border",
        config.bg,
        config.text,
        config.border
      )}
    >
      {config.label}
    </span>
  );
}

function SuspendedBadge({ suspended }: { suspended: boolean }) {
  return suspended ? (
    <span className="inline-flex items-center gap-1 border border-[#e2a29b] bg-[#fff0ef] px-2.5 py-0.5 text-xs font-medium text-[#9f2f25]">
      <Ban className="w-3 h-3" aria-hidden="true" />
      停用
    </span>
  ) : (
    <span className="inline-flex items-center gap-1 border border-[#9bc7a4] bg-[#f0faf2] px-2.5 py-0.5 text-xs font-medium text-[#17602a]">
      <CheckCircle2 className="w-3 h-3" aria-hidden="true" />
      正常
    </span>
  );
}

function TenantRow({ tenant, index }: { tenant: Tenant; index: number }) {
  return (
    <tr className="border-b border-border hover:bg-accent/30 transition-colors">
      <td className="px-4 py-3">
        <span className="font-mono text-sm text-foreground">
          {tenantPublicCode(index)}
        </span>
      </td>
      <td className="px-4 py-3">
        <span className="text-sm text-foreground font-medium">{tenantPublicName(tenant, index)}</span>
      </td>
      <td className="px-4 py-3">
        <MigrationModeBadge mode={tenant.migration_mode} />
      </td>
      <td className="px-4 py-3">
        <span className="flex items-center gap-1 text-sm text-muted-foreground font-mono">
          <DollarSign className="w-3.5 h-3.5" aria-hidden="true" />
          {tenantBudgetState(tenant)}
        </span>
      </td>
      <td className="px-4 py-3">
        <SuspendedBadge suspended={!tenant.is_active} />
      </td>
    </tr>
  );
}

function ProductCommandMap({
  inventory,
  tenants,
  loading,
}: {
  inventory: TenantAssetInventory | null;
  tenants: Tenant[];
  loading: boolean;
}) {
  const t = useTranslations("awooop.tenants.productCommandMap");
  const products = inventory?.products ?? [];
  const publicRoutes = inventory?.public_routes ?? [];
  const sourceRepos = inventory?.source_repos ?? [];
  const summary = inventory?.summary;
  const totalAssets = products.length + publicRoutes.length + sourceRepos.length;
  const ownerWaitingCount = products.filter(
    (item) =>
      item.owner_response_accepted_count === 0 ||
      item.coverage_status === "owner_response_required"
  ).length;
  const routePendingCount = publicRoutes.filter((item) => !item.route_smoke_accepted).length;
  const sourceBlockerCount = sourceRepos.reduce((total, item) => total + item.blocker_count, 0);
  const acceptedOwnerCount = summary?.owner_response_accepted_count ?? 0;
  const runtimeGateCount = summary?.runtime_gate_count ?? 0;
  const actionButtonCount = summary?.action_button_count ?? 0;
  const routeReadyCount = publicRoutes.filter((item) => item.route_smoke_accepted).length;
  const sourcePrimaryReadyCount = summary?.source_primary_ready_count ?? 0;
  const sourceCandidateCount = summary?.source_candidate_repo_count ?? sourceRepos.length;
  const topologyRows = [
    {
      key: "products",
      label: t("topology.products"),
      value: products.length || "--",
      Icon: Boxes,
      tone: "steady" as const,
      detail: t("topology.productsDetail", { tenants: tenants.length }),
    },
    {
      key: "routes",
      label: t("topology.routes"),
      value: publicRoutes.length || "--",
      Icon: Globe2,
      tone: routePendingCount > 0 ? "warn" as const : "steady" as const,
      detail: t("topology.routesDetail", { pending: routePendingCount }),
    },
    {
      key: "sources",
      label: t("topology.sources"),
      value: sourceRepos.length || "--",
      Icon: GitBranch,
      tone: sourceBlockerCount > 0 ? "warn" as const : "steady" as const,
      detail: t("topology.sourcesDetail", { blockers: sourceBlockerCount }),
    },
    {
      key: "gates",
      label: t("topology.gates"),
      value: acceptedOwnerCount,
      Icon: Lock,
      tone: "locked" as const,
      detail: t("topology.gatesDetail", { runtime: runtimeGateCount, actions: actionButtonCount }),
    },
  ];
  const commandMetrics = [
    {
      key: "totalAssets",
      value: totalAssets || "--",
      detail: t("metrics.totalAssetsDetail"),
      Icon: Network,
      tone: "steady" as const,
    },
    {
      key: "ownerWaiting",
      value: ownerWaitingCount,
      detail: t("metrics.ownerWaitingDetail"),
      Icon: ShieldCheck,
      tone: ownerWaitingCount > 0 ? "warn" as const : "steady" as const,
    },
    {
      key: "routePending",
      value: routePendingCount,
      detail: t("metrics.routePendingDetail"),
      Icon: Globe2,
      tone: routePendingCount > 0 ? "warn" as const : "steady" as const,
    },
    {
      key: "runtimeGate",
      value: runtimeGateCount,
      detail: t("metrics.runtimeGateDetail"),
      Icon: Lock,
      tone: runtimeGateCount === 0 ? "locked" as const : "warn" as const,
    },
  ];
  const decisionRows = [
    {
      key: "products",
      value: `${products.length}`,
      status: t("matrix.productsStatus"),
      detail: t("matrix.productsDetail"),
      tone: "steady" as const,
    },
    {
      key: "routes",
      value: `${routeReadyCount}/${publicRoutes.length}`,
      status: t("matrix.routesStatus", { pending: routePendingCount }),
      detail: t("matrix.routesDetail"),
      tone: routePendingCount > 0 ? "warn" as const : "steady" as const,
    },
    {
      key: "sources",
      value: `${sourcePrimaryReadyCount}/${sourceCandidateCount}`,
      status: t("matrix.sourcesStatus", { blockers: sourceBlockerCount }),
      detail: t("matrix.sourcesDetail"),
      tone: sourceBlockerCount > 0 ? "warn" as const : "steady" as const,
    },
    {
      key: "owner",
      value: `${acceptedOwnerCount}/${products.length}`,
      status: t("matrix.ownerStatus", { waiting: ownerWaitingCount }),
      detail: t("matrix.ownerDetail"),
      tone: "warn" as const,
    },
    {
      key: "runtime",
      value: `${runtimeGateCount}`,
      status: t("matrix.runtimeStatus", { actions: actionButtonCount }),
      detail: t("matrix.runtimeDetail"),
      tone: "locked" as const,
    },
  ];
  const drilldowns = [
    {
      href: "/observability",
      label: t("drilldowns.observability"),
      detail: t("drilldowns.observabilityDetail"),
    },
    {
      href: "/knowledge-base",
      label: t("drilldowns.knowledge"),
      detail: t("drilldowns.knowledgeDetail"),
    },
    {
      href: "/code-review",
      label: t("drilldowns.codeReview"),
      detail: t("drilldowns.codeReviewDetail"),
    },
  ];

  return (
    <section
      className="awooop-product-command-map overflow-hidden border border-[#d8d3c7] bg-white shadow-[0_1px_4px_rgba(0,0,0,0.05)]"
      data-testid="awooop-product-command-map"
    >
      <div className="grid gap-px bg-[#e0ddd4] xl:grid-cols-[minmax(0,0.72fr)_minmax(0,1.28fr)]">
        <div className="min-w-0 bg-[#262f3a] px-4 py-4 text-white">
          <div className="flex flex-wrap items-start justify-between gap-3">
            <div className="min-w-0">
              <p className="text-[11px] font-semibold uppercase tracking-[0.16em] text-[#8fd3ff]">
                {t("eyebrow")}
              </p>
              <h3 className="mt-2 font-['Syne'] text-2xl font-bold leading-tight">
                {t("title")}
              </h3>
              <p className="mt-3 hidden max-w-xl text-sm leading-6 text-[#d8e4ed] sm:block">
                {t("subtitle")}
              </p>
            </div>
            <span className="inline-flex shrink-0 border border-[#547089] bg-[#1b2530] px-2 py-1 text-xs font-semibold text-[#d8e4ed]">
              {loading ? t("loading") : t("badge")}
            </span>
          </div>

          <div className="mt-5 grid gap-2 sm:grid-cols-2">
            {commandMetrics.map(({ key, value, detail, Icon, tone }) => (
              <div key={key} className="min-w-0 border border-[#465a6a] bg-[#1d2732] px-3 py-3">
                <div className="flex items-start justify-between gap-3">
                  <div className="min-w-0">
                    <p className="text-[11px] font-semibold text-[#9fb3c4]">
                      {t(`metrics.${key}` as never)}
                    </p>
                    <p className="mt-2 font-mono text-2xl font-semibold text-white">{value}</p>
                  </div>
                  <span className={cn("flex h-8 w-8 shrink-0 items-center justify-center border", assetToneClass(tone))}>
                    <Icon className="h-4 w-4" aria-hidden="true" />
                  </span>
                </div>
                <p className="mt-2 hidden text-xs leading-5 text-[#c6d4df] sm:block">{detail}</p>
              </div>
            ))}
          </div>
        </div>

        <div className="min-w-0 bg-white">
          <div className="grid gap-px bg-[#e0ddd4] md:grid-cols-4">
            {topologyRows.map(({ key, label, value, Icon, tone, detail }) => (
              <div key={key} className="min-w-0 bg-white px-4 py-4">
                <div className="flex items-start justify-between gap-3">
                  <div className="min-w-0">
                    <p className="text-xs font-semibold text-[#77736a]">{label}</p>
                    <p className="mt-2 font-mono text-2xl font-semibold text-[#141413]">{value}</p>
                  </div>
                  <span className={cn("flex h-8 w-8 shrink-0 items-center justify-center border", assetToneClass(tone))}>
                    <Icon className="h-4 w-4" aria-hidden="true" />
                  </span>
                </div>
                <p className="mt-3 hidden text-xs leading-5 text-[#5f5b52] sm:block">{detail}</p>
              </div>
            ))}
          </div>

          <div className="grid gap-px bg-[#e0ddd4] lg:grid-cols-[minmax(0,1fr)_320px]">
            <div className="min-w-0 bg-[#faf9f3] p-4">
              <div className="flex flex-wrap items-center justify-between gap-2">
                <div className="min-w-0">
                  <p className="text-xs font-semibold text-[#77736a]">{t("matrixTitle")}</p>
                  <p className="mt-1 text-sm font-semibold text-[#141413]">{t("matrixDetail")}</p>
                </div>
                <span className="border border-[#d8d3c7] bg-white px-2 py-1 text-xs font-semibold text-[#5f5b52]">
                  {t("matrixBadge")}
                </span>
              </div>

              <div className="mt-4 grid gap-2">
                {decisionRows.map(({ key, value, status, detail, tone }) => (
                  <div
                    key={key}
                    className="grid gap-3 border border-[#e0ddd4] bg-white px-3 py-3 sm:grid-cols-[112px_minmax(0,1fr)_minmax(0,1.2fr)] sm:items-center"
                  >
                    <div className="min-w-0">
                      <p className="text-[11px] font-semibold text-[#77736a]">
                        {t(`matrix.${key}` as never)}
                      </p>
                      <p className="mt-1 font-mono text-2xl font-semibold text-[#141413]">{value}</p>
                    </div>
                    <div className={cn("min-w-0 border px-2 py-1 text-xs font-semibold", assetToneClass(tone))}>
                      {status}
                    </div>
                    <p className="hidden min-w-0 text-xs leading-5 text-[#5f5b52] sm:block">{detail}</p>
                  </div>
                ))}
              </div>
            </div>

            <div className="min-w-0 bg-white p-4">
              <p className="text-xs font-semibold text-[#77736a]">{t("drilldownTitle")}</p>
              <div className="mt-3 grid gap-2">
                {drilldowns.map((item) => (
                  <Link
                    key={item.href}
                    href={item.href}
                    className="group grid grid-cols-[minmax(0,1fr)_20px] items-center gap-3 border border-[#e0ddd4] bg-[#faf9f3] px-3 py-2 hover:border-[#d97757] hover:bg-white"
                  >
                    <span className="min-w-0">
                      <span className="block text-sm font-semibold text-[#141413]">{item.label}</span>
                      <span className="mt-1 hidden text-xs leading-5 text-[#5f5b52] sm:block">{item.detail}</span>
                    </span>
                    <ArrowRight className="h-4 w-4 text-[#77736a] group-hover:text-[#d97757]" aria-hidden="true" />
                  </Link>
                ))}
              </div>

              <div className="mt-4 border border-[#d9b36f] bg-[#fff7e8] px-3 py-3">
                <p className="text-xs font-semibold text-[#8a5a08]">{t("boundaryTitle")}</p>
                <p className="mt-2 text-xs leading-5 text-[#5f5b52]">
                  {t("boundaryDetail", {
                    owner: acceptedOwnerCount,
                    runtime: runtimeGateCount,
                    actions: actionButtonCount,
                  })}
                </p>
              </div>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

function SecurityTenantScopeCandidatePanel() {
  const t = useTranslations("awooop.tenants.securityTenantScopeCandidate");
  const metrics = [
    {
      label: t("metrics.primaryTenant"),
      value: "AWOOOI",
      detail: t("metrics.primaryTenantDetail"),
    },
    {
      label: t("metrics.securityEntry"),
      value: "IwoooS",
      detail: t("metrics.securityEntryDetail"),
    },
    {
      label: t("metrics.hostCoverage"),
      value: "3",
      detail: t("metrics.hostCoverageDetail"),
    },
    {
      label: t("metrics.policyMutations"),
      value: "0",
      detail: t("metrics.policyMutationsDetail"),
    },
  ];
  const scopes = [
    {
      name: "AWOOOI 第一租戶",
      detail: t("scopeRefs.awoooiTenant"),
    },
    {
      name: "IwoooS 資安鏡像",
      detail: t("scopeRefs.iwooosMirror"),
    },
    {
      name: "host:kali-readonly / host:dev-b / host:dev-a",
      detail: t("scopeRefs.hostCoverage"),
    },
    {
      name: "S4.9-S4.12 負責人回覆等待中",
      detail: t("scopeRefs.ownerResponse"),
    },
  ];

  return (
    <section className="overflow-hidden border border-[#e0ddd4] bg-white">
      <div className="sm:hidden">
        <div className="border-b border-[#e0ddd4] bg-[#faf9f3] px-2 py-2">
          <p className="text-[11px] font-semibold leading-4 text-[#141413]">{t("title")}</p>
          <span className="mt-1 inline-flex border border-[#9bb6d9] bg-[#eef5ff] px-1.5 py-0.5 text-[10px] font-semibold text-[#1f5b9b]">
            {t("badge")}
          </span>
        </div>
        <div className="grid gap-px bg-[#e0ddd4] text-[10px]">
          <div className="bg-white px-2 py-2">
            <p className="font-semibold text-[#77736a]">AWOOOI</p>
            <p className="mt-1 text-lg font-semibold text-[#141413]">租戶</p>
          </div>
          <div className="bg-white px-2 py-2">
            <p className="font-semibold text-[#77736a]">IwoooS</p>
            <p className="mt-1 text-lg font-semibold text-[#141413]">鏡像</p>
          </div>
          <div className="bg-white px-2 py-2">
            <p className="font-semibold text-[#77736a]">主機</p>
            <p className="mt-1 font-mono text-lg font-semibold text-[#141413]">3</p>
          </div>
          <div className="bg-white px-2 py-2">
            <p className="font-semibold text-[#77736a]">政策</p>
            <p className="mt-1 font-mono text-lg font-semibold text-[#141413]">0</p>
          </div>
        </div>
        <div className="space-y-2 bg-[#faf9f3] px-2 py-2 text-[10px] leading-4 text-[#5f5b52]">
          <p className="font-semibold text-[#141413]">{t("boundaryTitle")}</p>
          <p>{t("boundaryItems.runtimeLocked")}</p>
          <p>{t("boundaryItems.actionButtonsLocked")}</p>
          <Link
            href="/iwooos"
            className="inline-flex items-center gap-1 border border-[#d8d3c7] bg-white px-2 py-1 font-semibold text-[#141413] hover:border-[#d97757]"
          >
            IwoooS
            <ArrowRight className="h-3 w-3 text-[#77736a]" aria-hidden="true" />
          </Link>
        </div>
      </div>

      <div className="hidden sm:block">
      <div className="flex flex-wrap items-start justify-between gap-3 border-b border-[#e0ddd4] bg-[#faf9f3] px-4 py-3">
        <div className="flex items-start gap-2">
          <ShieldCheck className="mt-0.5 h-4 w-4 text-[#d97757]" aria-hidden="true" />
          <div>
            <h3 className="text-sm font-semibold text-[#141413]">{t("title")}</h3>
            <p className="mt-1 max-w-3xl text-xs leading-5 text-[#77736a]">{t("subtitle")}</p>
          </div>
        </div>
        <span className="inline-flex border border-[#9bb6d9] bg-[#eef5ff] px-2 py-0.5 text-xs font-semibold text-[#1f5b9b]">
          {t("badge")}
        </span>
      </div>

      <div className="grid gap-px bg-[#e0ddd4] md:grid-cols-2 xl:grid-cols-4">
        {metrics.map((item) => (
          <div key={item.label} className="bg-white px-4 py-3">
            <p className="text-xs font-semibold text-[#77736a]">{item.label}</p>
            <p className="mt-2 break-words font-mono text-2xl font-semibold text-[#141413]">{item.value}</p>
            <p className="mt-2 text-xs leading-5 text-[#5f5b52]">{item.detail}</p>
          </div>
        ))}
      </div>

      <div className="grid min-w-0 gap-4 p-4 xl:grid-cols-[1.1fr_0.9fr]">
        <div className="min-w-0 border border-[#e0ddd4] bg-white">
          <div className="border-b border-[#e0ddd4] bg-[#faf9f3] px-4 py-3 text-xs font-semibold text-[#141413]">
            {t("scopeRefsTitle")}
          </div>
          <div className="divide-y divide-[#eee9dd]">
            {scopes.map((item) => (
              <div key={item.name} className="px-4 py-3">
                <p className="break-words font-mono text-xs font-semibold text-[#141413]">{item.name}</p>
                <p className="mt-1 text-xs leading-5 text-[#5f5b52]">{item.detail}</p>
              </div>
            ))}
          </div>
        </div>

        <div className="min-w-0 border border-[#e0ddd4] bg-[#faf9f3] px-4 py-3">
          <p className="text-xs font-semibold text-[#77736a]">{t("boundaryLabel")}</p>
          <p className="mt-2 text-sm font-semibold text-[#141413]">{t("boundaryTitle")}</p>
          <p className="mt-2 text-xs leading-5 text-[#5f5b52]">{t("boundaryDetail")}</p>
          <div className="mt-4 grid gap-2 text-xs leading-5 text-[#141413]">
            {tenantScopeBoundaryItems.map((item) => (
              <span key={item}>{t(`boundaryItems.${item}` as never)}</span>
            ))}
          </div>
          <Link
            href="/iwooos"
            className="mt-4 inline-flex items-center gap-2 border border-[#d8d3c7] bg-white px-3 py-1.5 text-xs font-semibold text-[#141413] hover:border-[#d97757]"
          >
            {t("openIwooos")}
            <ArrowRight className="h-3.5 w-3.5 text-[#77736a]" aria-hidden="true" />
          </Link>
        </div>
      </div>
      </div>
    </section>
  );
}

function GitHubTenantReadinessScopePanel() {
  const t = useTranslations("awooop.tenants.githubTenantReadinessScope");

  return (
    <section className="overflow-hidden border border-[#e0ddd4] bg-white">
      <div className="flex flex-wrap items-start justify-between gap-3 border-b border-[#e0ddd4] bg-[#faf9f3] px-4 py-3">
        <div className="flex min-w-0 items-start gap-2">
          <GitBranch className="mt-0.5 h-4 w-4 shrink-0 text-[#d97757]" aria-hidden="true" />
          <div className="min-w-0">
            <h3 className="text-sm font-semibold text-[#141413]">{t("title")}</h3>
            <p className="mt-1 max-w-3xl text-xs leading-5 text-[#77736a]">{t("subtitle")}</p>
          </div>
        </div>
        <div className="flex flex-wrap items-center gap-2">
          <span className="inline-flex border border-[#d9b36f] bg-[#fff7e8] px-2 py-0.5 text-xs font-semibold text-[#8a5a08]">
            {t("badge")}
          </span>
          <Link
            href="/iwooos"
            className="inline-flex items-center gap-2 border border-[#d8d3c7] bg-white px-3 py-1.5 text-xs font-semibold text-[#141413] hover:border-[#d97757]"
          >
            {t("openIwooos")}
            <ArrowRight className="h-3.5 w-3.5 text-[#77736a]" aria-hidden="true" />
          </Link>
        </div>
      </div>

      <div className="grid gap-px bg-[#e0ddd4] md:grid-cols-2 xl:grid-cols-4">
        {githubTenantReadinessMetrics.map((metric) => {
          const Icon = metric.icon;
          return (
            <div key={metric.key} className="min-h-[122px] bg-white px-4 py-3">
              <div className="flex items-start justify-between gap-3">
                <div className="min-w-0">
                  <p className="text-xs font-semibold text-[#77736a]">
                    {t(`metrics.${metric.key}.label` as never)}
                  </p>
                  <p className="mt-2 break-words font-mono text-2xl font-semibold text-[#141413]">
                    {metric.value}
                  </p>
                </div>
                <span
                  className={cn(
                    "flex h-8 w-8 shrink-0 items-center justify-center border",
                    metric.tone === "warn" && "border-[#d9b36f] bg-[#fff7e8] text-[#8a5a08]",
                    metric.tone === "neutral" && "border-[#d8d3c7] bg-[#faf9f3] text-[#5f5b52]"
                  )}
                >
                  <Icon className="h-4 w-4" aria-hidden="true" />
                </span>
              </div>
              <p className="mt-3 text-xs leading-5 text-[#5f5b52]">
                {t(`metrics.${metric.key}.detail` as never)}
              </p>
            </div>
          );
        })}
      </div>

      <div className="grid min-w-0 gap-4 p-4 xl:grid-cols-[1.1fr_0.9fr]">
        <div className="min-w-0 border border-[#e0ddd4] bg-white">
          <div className="border-b border-[#e0ddd4] bg-[#faf9f3] px-4 py-3 text-xs font-semibold text-[#141413]">
            {t("scopeRefsTitle")}
          </div>
          <div className="divide-y divide-[#eee9dd]">
            {githubTenantReadinessScopes.map((scope) => (
              <div key={scope.key} className="grid gap-3 px-4 py-3 md:grid-cols-[minmax(0,1fr)_96px]">
                <div className="min-w-0">
                  <p className="break-words font-mono text-xs font-semibold text-[#141413]">
                    {scope.name}
                  </p>
                  <p className="mt-1 text-xs leading-5 text-[#5f5b52]">
                    {t(`scopeRefs.${scope.key}` as never)}
                  </p>
                </div>
                <div>
                  <span className="inline-flex border border-[#d9b36f] bg-[#fff7e8] px-2 py-0.5 font-mono text-xs font-semibold text-[#8a5a08]">
                    {scope.status}
                  </span>
                </div>
              </div>
            ))}
          </div>
        </div>

        <div className="min-w-0 border border-[#e0ddd4] bg-[#faf9f3] px-4 py-3">
          <p className="text-xs font-semibold text-[#77736a]">{t("boundaryLabel")}</p>
          <p className="mt-2 text-sm font-semibold text-[#141413]">{t("boundaryTitle")}</p>
          <p className="mt-2 text-xs leading-5 text-[#5f5b52]">{t("boundaryDetail")}</p>
          <div className="mt-4 grid gap-2 text-xs leading-5 text-[#141413]">
            {githubTenantReadinessBoundaries.map((boundary) => (
              <span key={boundary}>{t(`boundaryItems.${boundary}` as never)}</span>
            ))}
          </div>
        </div>
      </div>
    </section>
  );
}

function OwnerResponseValidationTenantScopePanel() {
  const t = useTranslations("awooop.tenants.ownerResponseValidationScope");
  const metrics = [
    {
      label: t("metrics.packets"),
      value: "4",
      detail: t("metrics.packetsDetail"),
    },
    {
      label: t("metrics.templates"),
      value: "24",
      detail: t("metrics.templatesDetail"),
    },
    {
      label: t("metrics.received"),
      value: "0",
      detail: t("metrics.receivedDetail"),
    },
    {
      label: t("metrics.accepted"),
      value: "0",
      detail: t("metrics.acceptedDetail"),
    },
    {
      label: t("metrics.tenantPolicyChanges"),
      value: "0",
      detail: t("metrics.tenantPolicyChangesDetail"),
    },
    {
      label: t("metrics.displaySections"),
      value: "8",
      detail: t("metrics.displaySectionsDetail"),
    },
  ];

  return (
    <section className="overflow-hidden border border-[#d9d4e6] bg-white">
      <div className="flex flex-wrap items-start justify-between gap-3 border-b border-[#d9d4e6] bg-[#f8f6fc] px-4 py-3">
        <div className="flex min-w-0 items-start gap-2">
          <ListChecks className="mt-0.5 h-4 w-4 shrink-0 text-[#6f5ca8]" aria-hidden="true" />
          <div className="min-w-0">
            <h3 className="text-sm font-semibold text-[#141413]">{t("title")}</h3>
            <p className="mt-1 max-w-3xl text-xs leading-5 text-[#5f5a70]">{t("subtitle")}</p>
          </div>
        </div>
        <div className="flex flex-wrap items-center gap-2">
          <span className="inline-flex border border-[#b7add8] bg-white px-2 py-0.5 text-xs font-semibold text-[#5b4b91]">
            {t("badge")}
          </span>
          <Link
            href="/iwooos"
            className="inline-flex items-center gap-2 border border-[#b7add8] bg-white px-3 py-1.5 text-xs font-semibold text-[#141413] hover:border-[#6f5ca8]"
          >
            {t("openIwooos")}
            <ArrowRight className="h-3.5 w-3.5 text-[#5f5a70]" aria-hidden="true" />
          </Link>
        </div>
      </div>

      <div className="grid gap-px bg-[#d9d4e6] md:grid-cols-2 xl:grid-cols-6">
        {metrics.map((item) => (
          <div key={item.label} className="min-h-[122px] bg-white px-4 py-3">
            <p className="text-xs font-semibold text-[#5f5a70]">{item.label}</p>
            <p className="mt-2 break-words font-mono text-2xl font-semibold text-[#141413]">{item.value}</p>
            <p className="mt-2 text-xs leading-5 text-[#4f4a60]">{item.detail}</p>
          </div>
        ))}
      </div>

      <div className="grid min-w-0 gap-4 p-4 xl:grid-cols-[1.1fr_0.9fr]">
        <div className="min-w-0 border border-[#d9d4e6] bg-white">
          <div className="border-b border-[#d9d4e6] bg-[#f8f6fc] px-4 py-3 text-xs font-semibold text-[#141413]">
            {t("scopeRefsTitle")}
          </div>
          <div className="divide-y divide-[#e8e3f2]">
            {ownerResponseValidationTenantRefs.map((item) => (
              <div key={item.key} className="grid gap-3 px-4 py-3 md:grid-cols-[72px_minmax(0,1fr)]">
                <span className="font-mono text-xs font-semibold text-[#141413]">{item.phase}</span>
                <div className="min-w-0">
                  <p className="text-sm font-semibold text-[#141413]">
                    {t(`scopeRefs.${item.key}.title` as never)}
                  </p>
                  <p className="mt-1 text-xs leading-5 text-[#4f4a60]">
                    {t(`scopeRefs.${item.key}.detail` as never)}
                  </p>
                </div>
              </div>
            ))}
          </div>
        </div>

        <div className="min-w-0 border border-[#d9d4e6] bg-[#f8f6fc] px-4 py-3">
          <p className="text-xs font-semibold text-[#5f5a70]">{t("boundaryLabel")}</p>
          <p className="mt-2 text-sm font-semibold text-[#141413]">{t("boundaryTitle")}</p>
          <p className="mt-2 text-xs leading-5 text-[#4f4a60]">{t("boundaryDetail")}</p>
          <div className="mt-4 grid gap-2 text-xs leading-5 text-[#141413]">
            {ownerResponseValidationTenantBoundaries.map((boundary) => (
              <span key={boundary}>{t(`boundaryItems.${boundary}` as never)}</span>
            ))}
          </div>
        </div>
      </div>
    </section>
  );
}

function GlobalAssetCoveragePanel({ inventory }: { inventory: TenantAssetInventory | null }) {
  const t = useTranslations("awooop.tenants.globalAssets");
  const summary = inventory?.summary;
  const products = inventory?.products ?? [];
  const publicRoutes = inventory?.public_routes ?? [];
  const sourceRepos = inventory?.source_repos ?? [];
  const visibleAssetCount = products.length + publicRoutes.length + sourceRepos.length;
  const categoryCounts = countBy(products, (item) => item.category);
  const productStatusCounts = countBy(products, (item) => item.coverage_status);
  const routeStatusCounts = countBy(publicRoutes, (item) => item.coverage_status);
  const routePreviewLimit = 18;
  const routePreview = publicRoutes.slice(0, routePreviewLimit);
  const remainingRouteCount = Math.max(publicRoutes.length - routePreview.length, 0);
  const ownerRequiredProducts = products.filter(
    (item) => item.coverage_status === "owner_response_required"
  ).length;
  const pendingRouteSmokeCount = publicRoutes.filter((item) => !item.route_smoke_accepted).length;
  const sourceBlockerCount = sourceRepos.reduce((total, item) => total + item.blocker_count, 0);
  const productStatusEntries = Object.entries(productStatusCounts);
  const routeStatusEntries = Object.entries(routeStatusCounts);
  const categoryEntries = Object.entries(categoryCounts);
  const sourceGateRows = [
    {
      label: t("sourceGate.primaryReady"),
      value: `${summary?.source_primary_ready_count ?? 0}/${summary?.source_candidate_repo_count ?? sourceRepos.length}`,
    },
    {
      label: t("sourceGate.ownerAccepted"),
      value: `${summary?.owner_response_accepted_count ?? 0}`,
    },
    {
      label: t("sourceGate.runtimeGate"),
      value: `${summary?.runtime_gate_count ?? 0}`,
    },
    {
      label: t("sourceGate.actionButtons"),
      value: `${summary?.action_button_count ?? 0}`,
    },
  ];
  const metrics = [
    {
      key: "products",
      value: summary?.product_surface_count ?? "--",
      Icon: Boxes,
      tone: "steady" as const,
    },
    {
      key: "routes",
      value: summary?.public_route_count ?? "--",
      Icon: Globe2,
      tone: "steady" as const,
    },
    {
      key: "repos",
      value: summary?.source_candidate_repo_count ?? "--",
      Icon: GitBranch,
      tone: "warn" as const,
    },
    {
      key: "tenants",
      value: summary?.tenant_table_count ?? "--",
      Icon: Building2,
      tone: "steady" as const,
    },
    {
      key: "ownerAccepted",
      value: summary?.owner_response_accepted_count ?? "--",
      Icon: ShieldCheck,
      tone: "warn" as const,
    },
    {
      key: "runtimeGate",
      value: summary?.runtime_gate_count ?? "--",
      Icon: Lock,
      tone: "locked" as const,
    },
  ];

  return (
    <section className="overflow-hidden border border-[#d8d3c7] bg-white shadow-[0_1px_4px_rgba(0,0,0,0.04)]">
      <div className="flex flex-wrap items-start justify-between gap-3 border-b border-[#e0ddd4] bg-[#faf9f3] px-4 py-3">
        <div className="flex min-w-0 items-start gap-2">
          <Boxes className="mt-0.5 h-4 w-4 shrink-0 text-[#d97757]" aria-hidden="true" />
          <div className="min-w-0">
            <p className="text-[11px] font-semibold uppercase tracking-[0.14em] text-[#a15f3b]">
              {t("eyebrow")}
            </p>
            <h3 className="mt-1 text-base font-semibold text-[#141413]">{t("title")}</h3>
            <p className="mt-1 hidden max-w-4xl text-xs leading-5 text-[#5f5b52] sm:block">{t("subtitle")}</p>
          </div>
        </div>
        <span className="inline-flex border border-[#9bc7a4] bg-[#f0faf2] px-2 py-0.5 text-xs font-semibold text-[#17602a]">
          {inventory ? t("badge") : t("loading")}
        </span>
      </div>

      <div className="grid gap-px bg-[#e0ddd4] sm:grid-cols-2 xl:grid-cols-6">
        {metrics.map(({ key, value, Icon, tone }) => (
          <div key={key} className="min-h-[122px] bg-white px-4 py-3">
            <div className="flex items-start justify-between gap-3">
              <div className="min-w-0">
                <p className="text-xs font-semibold text-[#77736a]">
                  {t(`metrics.${key}.label` as never)}
                </p>
                <p className="mt-2 break-words font-mono text-2xl font-semibold text-[#141413]">
                  {value}
                </p>
              </div>
              <span
                className={cn(
                  "flex h-8 w-8 shrink-0 items-center justify-center border",
                  assetToneClass(tone)
                )}
              >
                <Icon className="h-4 w-4" aria-hidden="true" />
              </span>
            </div>
            <p className="mt-3 hidden text-xs leading-5 text-[#5f5b52] sm:block">
              {t(`metrics.${key}.detail` as never)}
            </p>
          </div>
        ))}
      </div>

      <div className="grid gap-px border-b border-[#e0ddd4] bg-[#e0ddd4] xl:grid-cols-[0.95fr_1.05fr_1fr]">
        <div className="min-w-0 bg-[#2f2a24] px-4 py-4 text-white">
          <p className="text-[11px] font-semibold uppercase tracking-[0.14em] text-[#d9b36f]">
            {t("atlas.eyebrow")}
          </p>
          <p className="mt-2 text-3xl font-semibold leading-none">{visibleAssetCount || "--"}</p>
          <p className="mt-2 text-sm font-semibold">{t("atlas.totalAssets")}</p>
          <p className="mt-3 hidden text-xs leading-5 text-[#e5ddd0] sm:block">
            {t("atlas.totalDetail", {
              products: products.length,
              routes: publicRoutes.length,
              repos: sourceRepos.length,
            })}
          </p>
          <div className="mt-4 grid grid-cols-3 gap-2 text-[11px]">
            <div className="border border-[#5e5448] px-2 py-2">
              <p className="text-[#c8bfb2]">{t("labels.ownerRequired")}</p>
              <p className="mt-1 font-mono text-lg font-semibold text-white">{ownerRequiredProducts}</p>
            </div>
            <div className="border border-[#5e5448] px-2 py-2">
              <p className="text-[#c8bfb2]">{t("labels.routePending")}</p>
              <p className="mt-1 font-mono text-lg font-semibold text-white">{pendingRouteSmokeCount}</p>
            </div>
            <div className="border border-[#5e5448] px-2 py-2">
              <p className="text-[#c8bfb2]">{t("labels.sourceBlockers")}</p>
              <p className="mt-1 font-mono text-lg font-semibold text-white">{sourceBlockerCount}</p>
            </div>
          </div>
        </div>

        <div className="min-w-0 bg-white px-4 py-4">
          <div className="flex items-start justify-between gap-3">
            <div>
              <p className="text-xs font-semibold text-[#77736a]">{t("atlas.productMapTitle")}</p>
              <p className="mt-1 hidden text-sm font-semibold text-[#141413] sm:block">{t("atlas.productMapDetail")}</p>
            </div>
            <span className="border border-[#9bc7a4] bg-[#f0faf2] px-2 py-0.5 font-mono text-xs font-semibold text-[#17602a]">
              {products.length}
            </span>
          </div>
          <div className="mt-4 grid gap-2">
            {categoryEntries.map(([category, count]) => (
              <div key={category} className="grid grid-cols-[128px_minmax(0,1fr)_40px] items-center gap-2 text-[11px]">
                <span className="truncate font-semibold text-[#5f5b52]">
                  {assetCategoryLabel(category, t)}
                </span>
                <div className="h-2 border border-[#eee9dd] bg-[#faf9f3]">
                  <div
                    className="h-full bg-[#6f8f72]"
                    style={{
                      width: `${products.length ? Math.max(8, (count / products.length) * 100) : 0}%`,
                    }}
                  />
                </div>
                <span className="text-right font-mono font-semibold text-[#141413]">{count}</span>
              </div>
            ))}
          </div>
          <div className="mt-4 flex flex-wrap gap-2">
            {productStatusEntries.map(([status, count]) => (
              <span
                key={status}
                className="inline-flex border border-[#eee9dd] bg-[#faf9f3] px-2 py-1 text-[11px] text-[#5f5b52]"
              >
                <span className="font-semibold text-[#141413]">{assetStatusLabel(status, t)}</span>
                <span className="ml-1 font-mono">{count}</span>
              </span>
            ))}
          </div>
        </div>

        <div className="min-w-0 bg-white px-4 py-4">
          <div className="flex items-start justify-between gap-3">
            <div>
              <p className="text-xs font-semibold text-[#77736a]">{t("atlas.routeMapTitle")}</p>
              <p className="mt-1 hidden text-sm font-semibold text-[#141413] sm:block">{t("atlas.routeMapDetail")}</p>
            </div>
            <span className="border border-[#d9b36f] bg-[#fff7e8] px-2 py-0.5 font-mono text-xs font-semibold text-[#8a5a08]">
              {publicRoutes.length}
            </span>
          </div>
          <div className="mt-4 flex flex-wrap gap-1.5">
            {routePreview.map((route, index) => (
              <span
                key={route.domain}
                className="inline-flex max-w-full border border-[#eee9dd] bg-[#faf9f3] px-2 py-1 font-mono text-[10px] text-[#141413]"
                title={routePublicProductName(route, index)}
              >
                {route.domain}
              </span>
            ))}
            {remainingRouteCount > 0 && (
              <span className="inline-flex border border-[#d8d3c7] bg-white px-2 py-1 font-mono text-[10px] font-semibold text-[#5f5b52]">
                {t("atlas.moreRoutes", { count: remainingRouteCount })}
              </span>
            )}
          </div>
          <div className="mt-4 grid gap-2">
            {sourceGateRows.map((row) => (
              <div
                key={row.label}
                className="grid grid-cols-[minmax(0,1fr)_72px] items-center gap-3 border border-[#eee9dd] bg-[#faf9f3] px-2 py-1.5 text-[11px]"
              >
                <span className="truncate font-semibold text-[#5f5b52]">{row.label}</span>
                <span className="text-right font-mono font-semibold text-[#141413]">{row.value}</span>
              </div>
            ))}
          </div>
          <div className="mt-4 flex flex-wrap gap-2">
            {routeStatusEntries.map(([status, count]) => (
              <span
                key={status}
                className="inline-flex border border-[#eee9dd] bg-[#faf9f3] px-2 py-1 text-[11px] text-[#5f5b52]"
              >
                <span className="font-semibold text-[#141413]">{assetStatusLabel(status, t)}</span>
                <span className="ml-1 font-mono">{count}</span>
              </span>
            ))}
          </div>
        </div>
      </div>

      <div className="grid gap-4 p-4 xl:grid-cols-[minmax(0,1.05fr)_minmax(0,0.95fr)]">
        <details className="group min-w-0 overflow-hidden border border-[#e0ddd4] bg-white">
          <summary className="flex cursor-pointer list-none flex-wrap items-center justify-between gap-2 border-b border-[#e0ddd4] bg-[#faf9f3] px-4 py-3 [&::-webkit-details-marker]:hidden">
            <span className="min-w-0">
              <span className="block text-xs font-semibold text-[#141413]">{t("productsTitle")}</span>
              <span className="mt-1 block text-[11px] text-[#77736a]">
                {t("details.productsSummary", { count: products.length })}
              </span>
            </span>
            <span className="inline-flex items-center gap-2 font-mono text-xs font-semibold text-[#5f5b52]">
              {products.length} {t("itemsUnit")}
              <ChevronDown className="h-4 w-4 transition-transform group-open:rotate-180" aria-hidden="true" />
            </span>
          </summary>
          <div className="grid gap-px bg-[#eee9dd] md:grid-cols-2">
            {products.map((item, index) => (
              <article key={item.product_id} className="min-w-0 bg-white px-4 py-3">
                <div className="flex flex-wrap items-start justify-between gap-2">
                  <div className="min-w-0">
                    <p className="break-words text-sm font-semibold text-[#141413]">
                      {assetPublicProductName(item, index)}
                    </p>
                    <p className="mt-1 font-mono text-[11px] text-[#77736a]">
                      {assetPublicCode(index)} · {assetCategoryLabel(item.category, t)}
                    </p>
                  </div>
                  <AssetStatusBadge status={item.coverage_status} t={t} />
                </div>
                <div className="mt-3 grid grid-cols-3 gap-2 text-[11px]">
                  <div className="border border-[#eee9dd] bg-[#faf9f3] px-2 py-1.5">
                    <p className="text-[#77736a]">{t("labels.routes")}</p>
                    <p className="font-mono font-semibold text-[#141413]">{item.public_route_count}</p>
                  </div>
                  <div className="border border-[#eee9dd] bg-[#faf9f3] px-2 py-1.5">
                    <p className="text-[#77736a]">{t("labels.repos")}</p>
                    <p className="font-mono font-semibold text-[#141413]">{item.source_repo_count}</p>
                  </div>
                  <div className="border border-[#eee9dd] bg-[#faf9f3] px-2 py-1.5">
                    <p className="text-[#77736a]">{t("labels.gates")}</p>
                    <p className="font-mono font-semibold text-[#141413]">{item.runtime_gate_count}</p>
                  </div>
                </div>
                <p className="mt-3 break-words font-mono text-[11px] leading-4 text-[#5f5b52]">
                  {item.public_routes.join(" / ")}
                </p>
              </article>
            ))}
          </div>
        </details>

        <div className="min-w-0 border border-[#e0ddd4] bg-[#faf9f3] px-4 py-3">
          <p className="text-xs font-semibold text-[#77736a]">{t("boundaryTitle")}</p>
          <p className="mt-2 text-sm font-semibold text-[#141413]">{t("boundaryLead")}</p>
          <div className="mt-4 grid gap-2 text-xs leading-5 text-[#141413]">
            {globalAssetBoundaryItems.map((item) => (
              <span key={item}>{t(`boundaryItems.${item}` as never)}</span>
            ))}
          </div>
          <div className="mt-4 grid gap-2 text-xs leading-5 text-[#5f5b52]">
            <span className="font-semibold text-[#141413]">
              {inventory?.evidence_refs.length
                ? `已提交證據參照 ${inventory.evidence_refs.length} 項`
                : "等待證據參照"}
            </span>
            <span>完整證據路徑保留在只讀台帳與 guard，不在前台公開顯示。</span>
          </div>
        </div>
      </div>

      <div className="grid gap-4 border-t border-[#e0ddd4] bg-[#faf9f3] p-4 xl:grid-cols-2">
        <details className="group min-w-0 overflow-hidden border border-[#e0ddd4] bg-white">
          <summary className="flex cursor-pointer list-none flex-wrap items-center justify-between gap-2 border-b border-[#e0ddd4] px-4 py-3 [&::-webkit-details-marker]:hidden">
            <span className="min-w-0">
              <span className="block text-xs font-semibold text-[#141413]">{t("routesTitle")}</span>
              <span className="mt-1 block text-[11px] text-[#77736a]">
                {t("details.routesSummary", { count: publicRoutes.length, pending: pendingRouteSmokeCount })}
              </span>
            </span>
            <ChevronDown className="h-4 w-4 text-[#5f5b52] transition-transform group-open:rotate-180" aria-hidden="true" />
          </summary>
          <div data-testid="awooop-route-card-grid" className="grid gap-2 p-3 xl:hidden">
            {publicRoutes.map((route, index) => (
              <article key={route.domain} className="border border-[#eee9dd] bg-[#faf9f3] px-3 py-3">
                <div className="flex min-w-0 flex-wrap items-start justify-between gap-2">
                  <div className="min-w-0">
                    <p className="break-all font-mono text-xs font-semibold text-[#141413]">
                      {route.domain}
                    </p>
                    <p className="mt-1 break-words text-[11px] text-[#5f5b52]">
                      {routePublicProductName(route, index)}
                    </p>
                  </div>
                  <AssetStatusBadge status={route.coverage_status} t={t} />
                </div>
                <div className="mt-3 grid grid-cols-3 gap-2 text-[11px]">
                  <div className="border border-[#e0ddd4] bg-white px-2 py-1.5">
                    <p className="text-[#77736a]">{t("labels.upstream")}</p>
                    <p className="font-mono font-semibold text-[#141413]">{route.upstream_count}</p>
                  </div>
                  <div className="border border-[#e0ddd4] bg-white px-2 py-1.5">
                    <p className="text-[#77736a]">{t("labels.admin")}</p>
                    <p className="font-mono font-semibold text-[#141413]">{route.admin_route_count}</p>
                  </div>
                  <div className="border border-[#e0ddd4] bg-white px-2 py-1.5">
                    <p className="text-[#77736a]">{t("labels.realtime")}</p>
                    <p className="font-mono font-semibold text-[#141413]">{route.websocket_route_count}</p>
                  </div>
                </div>
              </article>
            ))}
          </div>
          <div className="hidden overflow-x-auto xl:block">
            <table className="w-full min-w-[760px] text-left text-xs">
              <thead className="bg-[#faf9f3] text-[#77736a]">
                <tr>
                  <th className="px-3 py-2 font-semibold">{t("columns.domain")}</th>
                  <th className="px-3 py-2 font-semibold">{t("columns.product")}</th>
                  <th className="px-3 py-2 font-semibold">{t("columns.status")}</th>
                  <th className="px-3 py-2 font-semibold">{t("columns.routeShape")}</th>
                </tr>
              </thead>
              <tbody className="divide-y divide-[#eee9dd]">
                {publicRoutes.map((route, index) => (
                  <tr key={route.domain}>
                    <td className="px-3 py-2 font-mono text-[#141413]">{route.domain}</td>
                    <td className="px-3 py-2 text-[#5f5b52]">
                      {routePublicProductName(route, index)}
                    </td>
                    <td className="px-3 py-2">
                      <AssetStatusBadge status={route.coverage_status} t={t} />
                    </td>
                    <td className="px-3 py-2 text-[#5f5b52]">
                      {t("labels.routeShape", {
                        upstream: route.upstream_count,
                        admin: route.admin_route_count,
                        websocket: route.websocket_route_count,
                      })}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </details>

        <details className="group min-w-0 overflow-hidden border border-[#e0ddd4] bg-white">
          <summary className="flex cursor-pointer list-none flex-wrap items-center justify-between gap-2 border-b border-[#e0ddd4] px-4 py-3 [&::-webkit-details-marker]:hidden">
            <span className="min-w-0">
              <span className="block text-xs font-semibold text-[#141413]">{t("reposTitle")}</span>
              <span className="mt-1 block text-[11px] text-[#77736a]">
                {t("details.reposSummary", { count: sourceRepos.length, blockers: sourceBlockerCount })}
              </span>
            </span>
            <ChevronDown className="h-4 w-4 text-[#5f5b52] transition-transform group-open:rotate-180" aria-hidden="true" />
          </summary>
          <div data-testid="awooop-source-card-grid" className="grid gap-2 p-3 xl:hidden">
            {sourceRepos.map((repo, index) => (
              <article
                key={`${repo.product_id}:${sourcePublicScopeCode(index)}:card`}
                className="border border-[#eee9dd] bg-[#faf9f3] px-3 py-3"
              >
                <div className="flex min-w-0 flex-wrap items-start justify-between gap-2">
                  <div className="min-w-0">
                    <p className="font-mono text-xs font-semibold text-[#141413]">
                      {sourcePublicScopeCode(index)}
                    </p>
                    <p className="mt-1 break-words text-[11px] text-[#5f5b52]">
                      {sourcePublicProductName(repo, index)}
                    </p>
                    <p className="mt-1 text-[10px] font-semibold text-[#77736a]">
                      {t("labels.redactedScope")} · {assetCategoryLabel(repo.category, t)}
                    </p>
                  </div>
                  <span className={cn("inline-flex border px-2 py-0.5 text-[11px] font-semibold", sourceRiskClass(repo.risk))}>
                    {sourceRiskLabel(repo.risk, t)}
                  </span>
                </div>
                <div className="mt-3 grid gap-2 text-[11px]">
                  <div className="border border-[#e0ddd4] bg-white px-2 py-1.5">
                    <p className="font-semibold text-[#141413]">
                      {sourceReadinessLabel(repo.readiness_state, t)}
                    </p>
                    <p className="mt-1 font-mono text-[#77736a]">
                      {t("labels.blockers", { count: repo.blocker_count })}
                    </p>
                  </div>
                  <div className="border border-[#e0ddd4] bg-white px-2 py-1.5">
                    <p className="text-[#77736a]">{t("columns.nextControl")}</p>
                    <p className="mt-1 break-words font-semibold text-[#141413]">
                      {sourceActionLabel(repo.readiness_state, t)}
                    </p>
                  </div>
                </div>
              </article>
            ))}
          </div>
          <div className="hidden overflow-x-auto xl:block">
            <table className="w-full min-w-[860px] text-left text-xs">
              <thead className="bg-[#faf9f3] text-[#77736a]">
                <tr>
                  <th className="px-3 py-2 font-semibold">{t("columns.repo")}</th>
                  <th className="px-3 py-2 font-semibold">{t("columns.product")}</th>
                  <th className="px-3 py-2 font-semibold">{t("columns.risk")}</th>
                  <th className="px-3 py-2 font-semibold">{t("columns.readiness")}</th>
                  <th className="px-3 py-2 font-semibold">{t("columns.nextControl")}</th>
                </tr>
              </thead>
              <tbody className="divide-y divide-[#eee9dd]">
                {sourceRepos.map((repo, index) => (
                  <tr key={`${repo.product_id}:${sourcePublicScopeCode(index)}`}>
                    <td className="px-3 py-2">
                      <div className="font-mono text-[#141413]">{sourcePublicScopeCode(index)}</div>
                      <div className="mt-1 text-[10px] font-semibold text-[#77736a]">
                        {t("labels.redactedScope")}
                      </div>
                      <div className="mt-1 text-[10px] text-[#77736a]">
                        {assetCategoryLabel(repo.category, t)}
                      </div>
                    </td>
                    <td className="px-3 py-2 text-[#5f5b52]">{sourcePublicProductName(repo, index)}</td>
                    <td className="px-3 py-2">
                      <span className={cn("inline-flex border px-2 py-0.5 font-semibold", sourceRiskClass(repo.risk))}>
                        {sourceRiskLabel(repo.risk, t)}
                      </span>
                    </td>
                    <td className="px-3 py-2 text-[#5f5b52]">
                      <div className="font-semibold text-[#141413]">
                        {sourceReadinessLabel(repo.readiness_state, t)}
                      </div>
                      <div className="mt-1 font-mono text-[11px] text-[#77736a]">
                        {t("labels.blockers", { count: repo.blocker_count })}
                      </div>
                    </td>
                    <td className="px-3 py-2 text-[#5f5b52]">
                      {sourceActionLabel(repo.readiness_state, t)}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </details>
      </div>
    </section>
  );
}

// =============================================================================
// Main Component
// =============================================================================

export default function TenantsPage() {
  const [tenants, setTenants] = useState<Tenant[]>([]);
  const [assetInventory, setAssetInventory] = useState<TenantAssetInventory | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  const fetchTenants = useCallback(async () => {
    try {
      setError(null);
      const res = await fetch(`${API_BASE}/api/v1/platform/tenants`);
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      const data: ApiResponse = await res.json();
      const rows = Array.isArray(data.tenants) ? data.tenants : data.items;
      setTenants(Array.isArray(rows) ? rows : []);
      setAssetInventory(data.asset_inventory ?? null);
    } catch (err) {
      setError(err instanceof Error ? err.message : "載入失敗");
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    fetchTenants();
  }, [fetchTenants]);

  return (
    <div className="space-y-6">
      {/* Page Header */}
      <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
        <div className="flex min-w-0 items-center gap-3">
          <Building2 className="w-5 h-5 text-brand-accent" aria-hidden="true" />
          <div className="min-w-0">
            <h2 className="text-lg font-semibold text-foreground">租戶管理</h2>
            <p className="break-words text-xs text-muted-foreground">
              {loading
                ? "載入中..."
                : `共 ${tenants.length} 個租戶 · ${assetInventory?.summary.product_surface_count ?? 0} 個產品 / 專案 · ${assetInventory?.summary.public_route_count ?? 0} 個網站入口`}
            </p>
          </div>
        </div>
        <button
          onClick={fetchTenants}
          disabled={loading}
          className="flex items-center gap-2 px-3 py-2 text-sm text-muted-foreground hover:text-foreground hover:bg-accent rounded-lg transition disabled:opacity-50"
          aria-label="重新整理租戶清單"
        >
          <RefreshCw className={cn("w-4 h-4", loading && "animate-spin")} aria-hidden="true" />
          重新整理
        </button>
      </div>

      <ProductCommandMap inventory={assetInventory} tenants={tenants} loading={loading} />

      <GlobalAssetCoveragePanel inventory={assetInventory} />

      <SecurityTenantScopeCandidatePanel />

      <GitHubTenantReadinessScopePanel />

      <OwnerResponseValidationTenantScopePanel />

      {/* Error State */}
      {error && (
        <div className="flex items-start gap-3 p-4 bg-red-900/20 border border-red-800/40 rounded-lg">
          <AlertCircle className="w-5 h-5 text-red-400 flex-shrink-0 mt-0.5" aria-hidden="true" />
          <div>
            <p className="text-sm font-medium text-red-300">無法載入租戶資料</p>
            <p className="text-xs text-red-400 mt-1">{error}</p>
          </div>
        </div>
      )}

      {/* Table */}
      <div className="overflow-hidden border border-[#e0ddd4] bg-white shadow-[0_1px_4px_rgba(0,0,0,0.05)]">
        <div className="overflow-x-auto">
          <table className="w-full" role="table" aria-label="租戶清單">
            <thead>
              <tr className="border-b border-border bg-muted/50">
                <th className="text-left px-4 py-3 text-xs font-medium text-muted-foreground uppercase tracking-wider">
                  租戶代號
                </th>
                <th className="text-left px-4 py-3 text-xs font-medium text-muted-foreground uppercase tracking-wider">
                  公開名稱
                </th>
                <th className="text-left px-4 py-3 text-xs font-medium text-muted-foreground uppercase tracking-wider">
                  模式
                </th>
                <th className="text-left px-4 py-3 text-xs font-medium text-muted-foreground uppercase tracking-wider">
                  預算狀態
                </th>
                <th className="text-left px-4 py-3 text-xs font-medium text-muted-foreground uppercase tracking-wider">
                  狀態
                </th>
              </tr>
            </thead>
            <tbody>
              {loading ? (
                // Loading skeleton
                Array.from({ length: 5 }).map((_, i) => (
                  <tr key={i} className="border-b border-border">
                    {Array.from({ length: 5 }).map((_, j) => (
                      <td key={j} className="px-4 py-3">
                        <div className="h-5 bg-muted animate-pulse rounded w-24" />
                      </td>
                    ))}
                  </tr>
                ))
              ) : tenants.length === 0 && !error ? (
                <tr>
                  <td colSpan={5} className="px-4 py-16 text-center">
                    <Building2 className="w-10 h-10 text-muted-foreground/30 mx-auto mb-3" aria-hidden="true" />
                    <p className="text-sm text-muted-foreground">尚無租戶資料</p>
                  </td>
                </tr>
              ) : (
                tenants.map((tenant, index) => (
                  <TenantRow key={tenant.project_id} tenant={tenant} index={index} />
                ))
              )}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}
