import type { ReactElement } from "react";
import { useEffect, useMemo, useState } from "react";

import { api } from "../../services/api/client";
import type { AccessToolId, AccessUserRole, AccessUserStatus, AdminAccessMatrixResponse, AdminAccessSummaryResponse, AdminAccessUserSummary, Tone } from "../../types/domain";
import { shortToken } from "../../utils";
import { StateTag } from "../shared/StateTag";

interface AccessState {
  loading: boolean;
  detailLoading: boolean;
  savingKey: string | null;
  users: AdminAccessUserSummary[];
  selectedUserId: string | null;
  summary: AdminAccessSummaryResponse | null;
  matrix: AdminAccessMatrixResponse | null;
  error: string | null;
}

const TOOLS: Array<{ id: AccessToolId; label: string; title: string }> = [
  { id: "hwpod", label: "hwpod", title: "HWPOD CLI" },
  { id: "unidesk_ssh", label: "UniDesk SSH", title: "UniDesk SSH passthrough" },
  { id: "trans_cmd", label: "trans cmd", title: "trans passthrough command" },
  { id: "github_pr", label: "GitHub PR", title: "GitHub PR tool" }
];

const initialState: AccessState = { loading: false, detailLoading: false, savingKey: null, users: [], selectedUserId: null, summary: null, matrix: null, error: null };

export function AccessView(): ReactElement {
  const [state, setState] = useState<AccessState>(initialState);

  async function load(): Promise<void> {
    setState((current) => ({ ...current, loading: true, error: null }));
    const [summary, users] = await Promise.all([api.adminAccessSummary(), api.adminAccessUsers()]);
    if (!summary.ok || !users.ok) {
      setState((current) => ({ ...current, loading: false, summary: summary.ok ? summary.data : current.summary, users: users.ok ? users.data?.users ?? [] : current.users, error: summary.error ?? users.error ?? "授权管理不可用" }));
      return;
    }
    const nextUsers = users.data?.users ?? [];
    const selectedUserId = state.selectedUserId && nextUsers.some((item) => item.user.id === state.selectedUserId)
      ? state.selectedUserId
      : nextUsers[0]?.user.id ?? null;
    setState((current) => ({ ...current, loading: false, summary: summary.data, users: nextUsers, selectedUserId, error: null }));
    if (selectedUserId) await loadUser(selectedUserId);
  }

  async function loadUser(userId: string): Promise<void> {
    if (!userId) return;
    setState((current) => ({ ...current, selectedUserId: userId, detailLoading: true, error: null }));
    const response = await api.adminAccessUser(userId);
    setState((current) => ({ ...current, detailLoading: false, matrix: response.ok ? response.data : current.matrix, error: response.ok ? null : response.error ?? "用户授权矩阵不可用" }));
  }

  async function updateUser(patch: { role?: AccessUserRole; status?: AccessUserStatus }): Promise<void> {
    const userId = state.matrix?.user.id ?? state.selectedUserId;
    if (!userId || state.savingKey) return;
    setState((current) => ({ ...current, savingKey: `user:${userId}`, error: null }));
    const response = await api.updateAdminAccessUser(userId, patch);
    setState((current) => ({
      ...current,
      savingKey: null,
      matrix: response.ok ? response.data?.access ?? current.matrix : current.matrix,
      users: response.ok && response.data?.access ? mergeUserSummaries(current.users, response.data.access) : current.users,
      error: response.ok ? null : response.error ?? "用户状态更新失败"
    }));
  }

  async function toggleTool(toolId: AccessToolId, allowed: boolean): Promise<void> {
    const userId = state.matrix?.user.id ?? state.selectedUserId;
    if (!userId || state.savingKey) return;
    const savingKey = `tool:${userId}:${toolId}`;
    setState((current) => ({ ...current, savingKey, error: null }));
    const response = await api.setAdminAccessTool(userId, toolId, allowed);
    setState((current) => ({
      ...current,
      savingKey: null,
      matrix: response.ok ? response.data?.access ?? current.matrix : current.matrix,
      users: response.ok && response.data?.access ? mergeUserSummaries(current.users, response.data.access) : current.users,
      error: response.ok ? null : response.error ?? "工具授权更新失败"
    }));
  }

  useEffect(() => { void load(); }, []);

  const selectedUser = state.matrix?.user ?? state.users.find((item) => item.user.id === state.selectedUserId)?.user ?? null;
  const statusTone = state.error ? "blocked" : state.loading || state.detailLoading ? "pending" : "source";
  const statusLabel = state.error ? "阻塞" : state.loading || state.detailLoading ? "加载中" : `${state.users.length} 个用户`;
  const openFga = state.matrix?.openfga ?? state.summary?.openfga ?? null;
  const openFgaTone = openFgaStatusTone(openFga?.mode, openFga?.ready, openFga?.degraded);
  const tupleCount = state.matrix?.tuples?.length ?? selectedSummary(state.users, state.selectedUserId)?.tupleCount ?? 0;
  const activeToolCount = useMemo(() => TOOLS.filter((tool) => state.matrix?.tools?.[tool.id] === true).length, [state.matrix]);

  return (
    <section className="view access-view" id="access" data-view="access" aria-labelledby="access-title">
      <div className="workspace-panel access-panel">
        <div className="panel-title-row">
          <div><p className="eyebrow">管理员</p><h2 id="access-title">授权管理</h2></div>
          <div className="panel-title-actions"><StateTag id="access-status" tone={statusTone}>{statusLabel}</StateTag><button className="command-button secondary" id="access-refresh" type="button" disabled={state.loading} onClick={() => void load()}>{state.loading ? "刷新中" : "刷新"}</button></div>
        </div>
        {state.error ? <p className="access-error" role="alert">{state.error}</p> : null}
        <div className="access-layout">
          <aside className="access-user-panel" aria-label="用户列表">
            <div className="access-section-head"><h3>用户</h3><span className="mono">{state.users.length}</span></div>
            <div className="access-user-list" id="access-user-list" aria-live="polite">
              {state.users.length === 0 ? <p className="access-empty">无用户</p> : state.users.map((item) => <UserButton key={item.user.id ?? item.user.username} item={item} active={item.user.id === state.selectedUserId} onSelect={() => item.user.id ? void loadUser(item.user.id) : undefined} />)}
            </div>
          </aside>

          <section className="access-matrix-panel" aria-label="用户状态和工具授权">
            <div className="access-section-head">
              <div><h3>{selectedUser?.displayName || selectedUser?.username || "未选择用户"}</h3><span className="mono wrap">{selectedUser?.id ?? "-"}</span></div>
              <div className="access-user-controls">
                <label><span>角色</span><select value={selectedUser?.role ?? "user"} disabled={!selectedUser || Boolean(state.savingKey)} onChange={(event) => void updateUser({ role: event.currentTarget.value as AccessUserRole })}><option value="user">用户</option><option value="admin">管理员</option></select></label>
                <label><span>状态</span><select value={selectedUser?.status ?? "active"} disabled={!selectedUser || Boolean(state.savingKey)} onChange={(event) => void updateUser({ status: event.currentTarget.value as AccessUserStatus })}><option value="active">启用</option><option value="disabled">停用</option></select></label>
              </div>
            </div>
            <div className="access-metrics" aria-label="当前用户授权摘要"><span>tuples <strong>{tupleCount}</strong></span><span>tools <strong>{activeToolCount}</strong></span></div>
            <div className="access-user-detail-card">
              <dl className="access-openfga-grid">
                <div><dt>user</dt><dd className="mono wrap">{selectedUser?.username ?? selectedUser?.id ?? "-"}</dd></div>
                <div><dt>role</dt><dd>{selectedUser?.role ?? "user"}</dd></div>
                <div><dt>status</dt><dd>{selectedUser?.status ?? "active"}</dd></div>
                <div><dt>updated</dt><dd>{state.detailLoading ? "loading" : "ready"}</dd></div>
              </dl>
            </div>
          </section>

          <aside className="access-tool-panel" aria-label="工具授权和 OpenFGA 状态">
            <section className="access-status-panel" aria-label="OpenFGA 状态">
              <div className="access-section-head"><h3>OpenFGA</h3><StateTag tone={openFgaTone}>{openFga?.mode ?? "unknown"}</StateTag></div>
              <dl className="access-openfga-grid">
                <div><dt>ready</dt><dd>{String(openFga?.ready ?? false)}</dd></div>
                <div><dt>store</dt><dd className="mono wrap">{shortToken(openFga?.storeId, 18)}</dd></div>
                <div><dt>model</dt><dd className="mono wrap">{shortToken(openFga?.modelId, 18)}</dd></div>
              </dl>
            </section>
            <section className="access-tools" aria-label="工具授权">
              <div className="access-section-head"><h3>工具</h3><span className="mono">{TOOLS.length}</span></div>
              <div className="access-tool-list">
                {TOOLS.map((tool) => {
                  const key = `tool:${selectedUser?.id ?? ""}:${tool.id}`;
                  return <div className="access-tool-row" key={tool.id}><div><strong>{tool.label}</strong><span>{tool.title}</span></div><PermissionSwitch checked={state.matrix?.tools?.[tool.id] === true} disabled={!selectedUser || Boolean(state.savingKey && state.savingKey !== key)} busy={state.savingKey === key} label={`${tool.title} can_use`} onChange={(checked) => void toggleTool(tool.id, checked)} /></div>;
                })}
              </div>
            </section>
          </aside>
        </div>
      </div>
    </section>
  );
}

function UserButton({ item, active, onSelect }: { item: AdminAccessUserSummary; active: boolean; onSelect(): void }): ReactElement {
  return (
    <button className={`access-user-row${active ? " active" : ""}`} type="button" aria-current={active ? "page" : undefined} onClick={onSelect}>
      <strong>{item.user.displayName || item.user.username || item.user.id}</strong>
      <span className="mono wrap">{item.user.username ?? item.user.id}</span>
      <span>{item.user.role ?? "user"} / {item.user.status ?? "active"} / tools {Object.values(item.tools ?? {}).filter(Boolean).length}</span>
    </button>
  );
}

function PermissionSwitch({ checked, disabled, busy, label, onChange }: { checked: boolean; disabled: boolean; busy: boolean; label: string; onChange(checked: boolean): void }): ReactElement {
  return <label className={`access-switch${busy ? " busy" : ""}`} title={label}><input type="checkbox" checked={checked} disabled={disabled || busy} aria-label={label} onChange={(event) => onChange(event.currentTarget.checked)} /><span aria-hidden="true" /></label>;
}

function selectedSummary(users: AdminAccessUserSummary[], userId: string | null): AdminAccessUserSummary | null {
  return users.find((item) => item.user.id === userId) ?? null;
}

function mergeUserSummaries(users: AdminAccessUserSummary[], access: AdminAccessMatrixResponse): AdminAccessUserSummary[] {
  return users.map((item) => item.user.id === access.user.id ? { ...item, user: access.user, tupleCount: access.tuples?.length ?? item.tupleCount, tools: access.tools } : item);
}

function openFgaStatusTone(mode: string | undefined, ready: boolean | undefined, degraded: boolean | undefined): Tone {
  if (degraded) return "blocked";
  if (mode === "enforce" && ready) return "ok";
  if (mode === "shadow") return "warn";
  if (mode === "off") return "source";
  return ready ? "ok" : "pending";
}
