import type { AccessToolId, AccessUserRole, AccessUserStatus, AdminAccessMatrixResponse, AdminAccessSummaryResponse, AdminAccessUsersResponse, AuthUser } from "@/types";

export interface AccessUserRow extends Record<string, unknown> {
  id: string;
  username: string;
  displayName: string;
  role: AccessUserRole;
  status: AccessUserStatus;
  tupleCount: number;
  toolCount: number;
  tools: Record<string, boolean>;
  source: Record<string, unknown>;
}

export interface AccessToolRow extends Record<string, unknown> {
  id: AccessToolId;
  label: string;
  allowed: boolean;
}

export interface AccessSummaryView {
  contractVersion: string;
  users: number;
  tuples: number;
  toolTuples: number;
  openfga: Record<string, unknown>;
  toolIds: string[];
}

const TOOL_LABELS: Record<string, string> = {
  hwpod: "HWPOD CLI",
  unidesk_ssh: "UniDesk SSH",
  trans_cmd: "trans passthrough",
  github_pr: "GitHub PR"
};

export function normalizeAccessSummary(payload: AdminAccessSummaryResponse | null): AccessSummaryView {
  const record = objectRecord(payload);
  const summary = objectRecord(record?.summary) ?? record ?? {};
  const counts = objectRecord(summary?.counts);
  const supported = objectRecord(summary?.supported);
  const openfga = objectRecord(summary?.openfga) ?? {};
  return {
    contractVersion: text(summary?.contractVersion) || "admin-access-v1",
    users: numberValue(counts?.users),
    tuples: numberValue(counts?.tuples),
    toolTuples: numberValue(counts?.toolTuples),
    openfga,
    toolIds: stringArray(supported?.toolIds)
  };
}

export function normalizeAccessUsers(payload: AdminAccessUsersResponse | null): AccessUserRow[] {
  const record = objectRecord(payload);
  const rows = firstArray(record?.users, record?.items, objectRecord(record?.data)?.users, objectRecord(record?.data)?.items);
  return rows.map((item, index) => normalizeUserRow(item, index)).filter((row) => row.id);
}

export function normalizeAccessDetail(payload: AdminAccessMatrixResponse | null): { user: AccessUserRow | null; tools: AccessToolRow[]; tuples: Record<string, unknown>[]; openfga: Record<string, unknown> } {
  const record = objectRecord(payload);
  const user = record ? normalizeUserRow(record, 0) : null;
  const tools = normalizeTools(record?.tools, Object.keys(user?.tools ?? {}));
  return {
    user: user?.id ? user : null,
    tools,
    tuples: firstArray(record?.tuples),
    openfga: objectRecord(record?.openfga) ?? {}
  };
}

export function normalizeTools(value: unknown, fallbackIds: string[] = []): AccessToolRow[] {
  if (Array.isArray(value)) {
    return value.map((item) => {
      const record = objectRecord(item) ?? {};
      const id = text(record.id ?? record.toolId ?? record.name);
      return { id, label: text(record.label) || TOOL_LABELS[id] || id, allowed: booleanValue(record.allowed ?? record.canUse ?? record.enabled) };
    }).filter((row) => row.id);
  }
  const record = objectRecord(value) ?? {};
  const ids = Array.from(new Set([...Object.keys(record), ...fallbackIds, ...Object.keys(TOOL_LABELS)])).filter(Boolean);
  return ids.map((id) => ({ id, label: TOOL_LABELS[id] || id, allowed: booleanValue(record[id]) }));
}

export function accessUserLabel(user: Pick<AccessUserRow, "displayName" | "username" | "id"> | AuthUser | null | undefined): string {
  const record = objectRecord(user);
  return text(record?.displayName ?? record?.name ?? record?.username ?? record?.id) || "unknown";
}

function normalizeUserRow(value: unknown, index: number): AccessUserRow {
  const record = objectRecord(value) ?? {};
  const nestedUser = objectRecord(record.user);
  const user = nestedUser ?? record;
  const toolsObject = normalizeToolObject(record.tools ?? user.tools);
  const id = text(user.id ?? user.userId ?? record.userId ?? user.username ?? record.username) || `user-${index}`;
  return {
    id,
    username: text(user.username),
    displayName: text(user.displayName ?? user.name),
    role: text(user.role) || "member",
    status: text(user.status) || "active",
    tupleCount: numberValue(record.tupleCount ?? user.tupleCount),
    toolCount: Object.values(toolsObject).filter(Boolean).length,
    tools: toolsObject,
    source: record
  };
}

function normalizeToolObject(value: unknown): Record<string, boolean> {
  const record = objectRecord(value) ?? {};
  const out: Record<string, boolean> = {};
  for (const [key, allowed] of Object.entries(record)) out[key] = booleanValue(allowed);
  return out;
}

function objectRecord(value: unknown): Record<string, unknown> | null {
  return value && typeof value === "object" && !Array.isArray(value) ? value as Record<string, unknown> : null;
}

function firstArray(...values: unknown[]): Record<string, unknown>[] {
  for (const value of values) if (Array.isArray(value)) return value.filter((item): item is Record<string, unknown> => Boolean(objectRecord(item)));
  return [];
}

function stringArray(value: unknown): string[] {
  return Array.isArray(value) ? value.map((item) => text(item)).filter(Boolean) : [];
}

function text(value: unknown): string {
  return typeof value === "string" ? value.trim() : "";
}

function numberValue(value: unknown): number {
  const number = Number(value ?? 0);
  return Number.isFinite(number) ? number : 0;
}

function booleanValue(value: unknown): boolean {
  if (typeof value === "boolean") return value;
  if (typeof value === "string") return ["1", "true", "yes", "allowed", "enabled"].includes(value.toLowerCase());
  return Boolean(value);
}
