// 运维控制台 → Gateway 控制面 API（带 JWT 鉴权；/admin 受 RequireAdmin 保护）。
export const GATEWAY: string =
  (import.meta.env.VITE_GATEWAY as string | undefined) ?? "http://localhost:8080";
const ADMIN = `${GATEWAY}/api/v1/admin`;

// ---- 鉴权（JWT，存 localStorage）----
const TOKEN_KEY = "sdx_admin_token";
let token = typeof localStorage !== "undefined" ? localStorage.getItem(TOKEN_KEY) ?? "" : "";

export function setToken(t: string): void {
  token = t;
  try {
    localStorage.setItem(TOKEN_KEY, t);
  } catch {
    /* ignore */
  }
}
export function clearToken(): void {
  token = "";
  try {
    localStorage.removeItem(TOKEN_KEY);
  } catch {
    /* ignore */
  }
}
export function getToken(): string {
  return token;
}

function authHeaders(json = false): Record<string, string> {
  const h: Record<string, string> = token ? { Authorization: `Bearer ${token}` } : {};
  if (json) h["Content-Type"] = "application/json";
  return h;
}

// guard 在 401(未登录) 时清令牌并广播登出（403=已登录但非管理员，照常抛错）。
function guard(res: Response): Response {
  if (res.status === 401) {
    clearToken();
    if (typeof window !== "undefined") window.dispatchEvent(new Event("sdx:logout"));
  }
  return res;
}

export interface AuthUser {
  id: string;
  email: string;
  name?: string;
}

export async function login(email: string, password: string): Promise<AuthUser> {
  const res = await fetch(`${GATEWAY}/api/v1/auth/login`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ email, password }),
  });
  const data = (await res.json()) as { token?: string; user?: AuthUser; error?: string };
  if (!res.ok || !data.token || !data.user) throw new Error(data.error ?? `登录失败: ${res.status}`);
  setToken(data.token);
  return data.user;
}

export async function me(): Promise<AuthUser | null> {
  if (!token) return null;
  const res = await fetch(`${GATEWAY}/api/v1/auth/me`, { headers: authHeaders() });
  if (!res.ok) {
    clearToken();
    return null;
  }
  return ((await res.json()) as { user?: AuthUser }).user ?? null;
}

// ---- 模型配置（id 为雪花字符串）----
export type Kind = "chat" | "embedding";

export interface Model {
  id: string;
  kind: Kind;
  provider: string;
  base_url: string;
  api_key: string; // 列表里是脱敏值
  model: string;
  active: boolean;
}

export interface ModelInput {
  id?: string;
  kind: Kind;
  provider: string;
  base_url: string;
  api_key: string;
  model: string;
}

export async function listModels(kind: Kind): Promise<Model[]> {
  const res = guard(await fetch(`${ADMIN}/models?kind=${kind}`, { headers: authHeaders() }));
  if (!res.ok) throw new Error(`list failed: ${res.status}`);
  return ((await res.json()) as { models: Model[] }).models;
}

export async function saveModel(m: ModelInput): Promise<string> {
  const res = guard(await fetch(`${ADMIN}/models`, { method: "POST", headers: authHeaders(true), body: JSON.stringify(m) }));
  const data = (await res.json()) as { id?: string; error?: string };
  if (!res.ok) throw new Error(data.error ?? `save failed: ${res.status}`);
  return data.id ?? "";
}

export async function setActive(id: string): Promise<void> {
  const res = guard(await fetch(`${ADMIN}/models/${id}/active`, { method: "POST", headers: authHeaders() }));
  if (!res.ok) throw new Error(`activate failed: ${res.status}`);
}

export async function deleteModel(id: string): Promise<void> {
  const res = guard(await fetch(`${ADMIN}/models/${id}`, { method: "DELETE", headers: authHeaders() }));
  if (!res.ok) throw new Error(`delete failed: ${res.status}`);
}

export async function testModel(m: ModelInput): Promise<{ ok: boolean; message: string }> {
  const res = guard(await fetch(`${ADMIN}/models/test`, { method: "POST", headers: authHeaders(true), body: JSON.stringify(m) }));
  return (await res.json()) as { ok: boolean; message: string };
}

// ---- 计价（token↔真钱，按模型分输入/输出）----
export interface Pricing {
  model_id: string;
  input_per_1k: number;
  output_per_1k: number;
  currency: string;
}

export async function listPricing(): Promise<Pricing[]> {
  const res = guard(await fetch(`${ADMIN}/pricing`, { headers: authHeaders() }));
  if (!res.ok) throw new Error(`list pricing failed: ${res.status}`);
  return ((await res.json()) as { pricing: Pricing[] }).pricing ?? [];
}

export async function savePricing(p: Pricing): Promise<void> {
  const res = guard(await fetch(`${ADMIN}/pricing`, { method: "PUT", headers: authHeaders(true), body: JSON.stringify(p) }));
  if (!res.ok) {
    const d = (await res.json().catch(() => ({}))) as { error?: string };
    throw new Error(d.error ?? `save pricing failed: ${res.status}`);
  }
}

// gatewayOnline 用公开的 /healthz 探活（不受鉴权影响）。
export async function gatewayOnline(): Promise<boolean> {
  try {
    const res = await fetch(`${GATEWAY}/healthz`);
    return res.ok;
  } catch {
    return false;
  }
}

// —— 服务状态：基建 / 应用服务探活 + MCP 工具注册 ——
export interface StatusItem {
  name: string;
  up: boolean;
  detail?: string;
  latency_ms?: number;
}
export interface ToolInfo {
  name: string;
  cn: string;
  desc: string;
}
export interface ToolGroup {
  server: string;
  up: boolean;
  tools: ToolInfo[] | null;
}
export interface SystemStatus {
  checked_at: string;
  infra: StatusItem[];
  services: StatusItem[];
  tools: ToolGroup[];
}

export async function getStatus(): Promise<SystemStatus> {
  const res = guard(await fetch(`${ADMIN}/status`, { headers: authHeaders() }));
  if (!res.ok) throw new Error(`status failed: ${res.status}`);
  return (await res.json()) as SystemStatus;
}

// —— 工作台概览（仪表盘聚合）——
// /api/v1/stats/overview 在 RequireAuth 组下；Task/Eval 表无 owner，故任务/评测口径为全局。
export interface DayCount {
  key: string;
  count: number;
}
export interface RecentRun {
  task_id: string;
  status: string;
  detail: string;
  at: string;
}
export interface Overview {
  tasks_today: number;
  tasks_total: number;
  status_count: DayCount[]; // 近 7 天终态分布
  task_trend: DayCount[]; // 近 7 天每日任务数（仅含有任务的天）
  eval_avg: number;
  faithful_avg: number; // 仅有来源的评测；无来源时为 0
  eval_count: number;
  kb_docs: number;
  kb_count: number;
  tokens_today: number;
  daily_budget: number; // 0 = 不限额
  token_trend: DayCount[];
  recent_runs: RecentRun[];
  services: Record<string, boolean>;
}

export async function statsOverview(): Promise<Overview> {
  const res = guard(await fetch(`${GATEWAY}/api/v1/stats/overview`, { headers: authHeaders() }));
  if (!res.ok) throw new Error(`overview failed: ${res.status}`);
  return (await res.json()) as Overview;
}

// —— 管理端系统级聚合（控制塔口径，RequireAdmin）——
// 区别于 statsOverview（桌面端个人工作台）：这里一律全平台口径——全部用户/任务/评测/模型态/提示词态/健康。
// 单模型运行时健康态（failover 链上主/备各一条）。
export interface ModelHealthItem {
  provider: string;
  model: string;
  role: string; // primary / fallback
  state: string; // closed(在线) / open(熔断中) / half-open(半开探测) / single(无备用链)
  fails: number;
}

export interface AdminOverview {
  users: number;
  kb_count: number; // 全平台知识库数
  kb_docs: number; // 全平台文档数
  tasks_today: number;
  tasks_total: number;
  status_count: DayCount[];
  task_trend: DayCount[];
  eval_avg: number;
  faithful_avg: number;
  eval_count: number;
  models: {
    chat_count: number;
    embedding_count: number;
    active_chat: string;
    active_embedding: string;
    fallbacks: number;
    health: ModelHealthItem[]; // 运行时每模型 failover/熔断态（来自 dispatcher）
  };
  prompts: { managed: number; overrides: number };
  services: Record<string, boolean>;
  checked_at: string;
}

export async function adminOverview(): Promise<AdminOverview> {
  const res = guard(await fetch(`${ADMIN}/overview`, { headers: authHeaders() }));
  if (!res.ok) throw new Error(`admin overview failed: ${res.status}`);
  return (await res.json()) as AdminOverview;
}

// —— 审计 / 安全事件（敏感操作留痕 + 护栏命中）——
export interface AuditEntry {
  id: string;
  actor: string; // 操作者 uid
  action: string; // POST / PUT / DELETE / PATCH
  route: string;
  path: string;
  status: number;
  ip: string;
  detail: string;
  at: string;
}
export interface GuardrailEventItem {
  id: string;
  actor: string;
  kind: string; // blocked / suspect
  reason: string;
  signals: string; // JSON 数组字符串
  method: string;
  path: string;
  ip: string;
  at: string;
}

export async function listAudit(limit = 50, offset = 0): Promise<AuditEntry[]> {
  const res = guard(await fetch(`${ADMIN}/audit?limit=${limit}&offset=${offset}`, { headers: authHeaders() }));
  if (!res.ok) throw new Error(`audit failed: ${res.status}`);
  return ((await res.json()) as { logs?: AuditEntry[] }).logs ?? [];
}

export async function listGuardrailEvents(limit = 50, offset = 0): Promise<GuardrailEventItem[]> {
  const res = guard(await fetch(`${ADMIN}/guardrail-events?limit=${limit}&offset=${offset}`, { headers: authHeaders() }));
  if (!res.ok) throw new Error(`guardrail events failed: ${res.status}`);
  return ((await res.json()) as { events?: GuardrailEventItem[] }).events ?? [];
}

// —— Prompt 控制面（建版本 → 激活 → 控制面热下发各服务，不重启即生效）——
// 注意：prompt 路由在 RequireAuth 组下（/api/v1/prompts），不在 /admin 前缀内。
const PROMPTS = `${GATEWAY}/api/v1/prompts`;

export interface PromptVersion {
  key: string;
  version: number;
  active: boolean;
  note: string;
  content: string;
}

export interface PromptListResp {
  keys: string[]; // 平台受管的全部可配 key（即便还没建过版本）
  versions: PromptVersion[];
}

// 某 key 的聚合视图：版本按号倒序、当前激活版（无则 null = 回退代码内置默认）。
export interface PromptGroup {
  key: string;
  versions: PromptVersion[];
  active: PromptVersion | null;
}

// groupPrompts 把扁平的 {keys, versions} 归并成按 key 的分组（控制面页面的事实源）。
// 纯函数：保持 keys 的注册顺序，每组版本号倒序，挑出激活版。
export function groupPrompts(resp: PromptListResp): PromptGroup[] {
  const byKey = new Map<string, PromptVersion[]>();
  for (const k of resp.keys) byKey.set(k, []);
  for (const v of resp.versions) {
    if (!byKey.has(v.key)) byKey.set(v.key, []); // 容错：DB 有但 Known 未列的 key 也展示
    byKey.get(v.key)!.push(v);
  }
  return Array.from(byKey.entries()).map(([key, vs]) => {
    const versions = [...vs].sort((a, b) => b.version - a.version);
    return { key, versions, active: versions.find((v) => v.active) ?? null };
  });
}

export async function listPrompts(): Promise<PromptListResp> {
  const res = guard(await fetch(PROMPTS, { headers: authHeaders() }));
  if (!res.ok) throw new Error(`list prompts failed: ${res.status}`);
  const data = (await res.json()) as Partial<PromptListResp>;
  return { keys: data.keys ?? [], versions: data.versions ?? [] };
}

export async function createPromptVersion(key: string, content: string, note: string): Promise<number> {
  const res = guard(
    await fetch(`${PROMPTS}/version`, { method: "POST", headers: authHeaders(true), body: JSON.stringify({ key, content, note }) }),
  );
  const data = (await res.json()) as { version?: number; error?: string };
  if (!res.ok) throw new Error(data.error ?? `create version failed: ${res.status}`);
  return data.version ?? 0;
}

export async function activatePrompt(key: string, version: number): Promise<void> {
  const res = guard(
    await fetch(`${PROMPTS}/activate`, { method: "POST", headers: authHeaders(true), body: JSON.stringify({ key, version }) }),
  );
  const data = (await res.json()) as { error?: string; warn?: string };
  if (!res.ok) throw new Error(data.error ?? `activate failed: ${res.status}`);
  if (data.warn) throw new Error(data.warn); // 已激活但广播失败 → 当作错误提示运维
}

export async function deactivatePrompt(key: string): Promise<void> {
  const res = guard(await fetch(`${PROMPTS}/deactivate`, { method: "POST", headers: authHeaders(true), body: JSON.stringify({ key }) }));
  if (!res.ok) {
    const d = (await res.json().catch(() => ({}))) as { error?: string };
    throw new Error(d.error ?? `deactivate failed: ${res.status}`);
  }
}

// —— 用量 / 计费（SaaS P2 计量：token / 积分 / 成本，按租户）——
// 金额与积分均为「微单位」（×10⁻⁶）：展示时 ÷1e6。走 /admin/usage（系统级，跨租户）。
export interface UsageDay {
  day: string; // YYYYMMDD
  total_tok: number;
  credits_micro: number;
  cost_micros: number;
  task_count: number;
}
export interface UsageTenantSum {
  tenant_id: string;
  name: string;
  total_tok: number;
  credits_micro: number;
  cost_micros: number;
  task_count: number;
  balance_micro: number;
}
export interface UsageReport {
  from: string;
  to: string;
  tenant: string; // 空 = 全平台口径
  trend: UsageDay[];
  totals: { total_tok: number; credits_micro: number; cost_micros: number; task_count: number };
  balance_micro?: number; // 仅单租户口径
  tenants?: UsageTenantSum[]; // 仅全平台口径：各租户排行
}

export async function adminUsage(params?: { tenant?: string; from?: string; to?: string }): Promise<UsageReport> {
  const q = new URLSearchParams();
  if (params?.tenant) q.set("tenant", params.tenant);
  if (params?.from) q.set("from", params.from);
  if (params?.to) q.set("to", params.to);
  const qs = q.toString();
  const res = guard(await fetch(`${ADMIN}/usage${qs ? "?" + qs : ""}`, { headers: authHeaders() }));
  if (!res.ok) throw new Error(`usage failed: ${res.status}`);
  const d = (await res.json()) as UsageReport;
  return { ...d, trend: d.trend ?? [], tenants: d.tenants ?? [] }; // Go 空切片可能序列化为 null
}
