import type {
  AdminProfile,
  ManagedAdmin,
  PermissionNode,
  AdminUser,
  AdminUserDetail,
  AgentDebugResult,
  AgentDebugStreamComplete,
  AgentGenerationConfig,
  AgentRuntimeConfig,
  AiLogRecord,
  ApiResponse,
  ChatDetail,
  ChatMessageRecord,
  ChatRecord,
  ChatRecordQuery,
  ContentGenerationConfigDetail,
  ContentGenerationHistoryItem,
  ContentGenerationType,
  DashboardStats,
  PeakTrafficResult,
  TrafficGrain,
  EntitlementPlan,
  EntitlementBatchRenewResult,
  KnowledgeItem,
  KnowledgeContentSearchItem,
  KnowledgeDetail,
  KnowledgeSyncJob,
  KnowledgeVersionContent,
  MigrationSummary,
  KnowledgeBatchSyncResult,
  KnowledgeBatchUpdateResult,
  RetrievalLogItem,
  AttentionItem,
  ModelItem,
  SystemConfigItem,
  UserImportResult,
  UserEntitlementSummary,
  PageResult,
  PeriodicReportRecord,
  PromptDetail,
  PromptHistoryItem,
  QuestionInsightRefreshResult,
  QuestionInsightSummary,
  SsoAuditItem,
  SsoClientItem,
  SsoIdentityItem,
  TopicSessionRecord,
  TopicSummaryRecord,
} from "../types/api";

const API_BASE = import.meta.env.VITE_API_BASE_URL ?? "/api";
const TOKEN_KEY = "ai-kb-admin-token";

export function getToken() {
  return window.localStorage.getItem(TOKEN_KEY);
}

export function saveToken(token: string) {
  window.localStorage.setItem(TOKEN_KEY, token);
}

export function clearToken() {
  window.localStorage.removeItem(TOKEN_KEY);
}

async function request<T>(path: string, init: RequestInit = {}): Promise<T> {
  const headers = new Headers(init.headers);
  headers.set("Content-Type", "application/json");
  const token = getToken();
  if (token) headers.set("Authorization", `Bearer ${token}`);
  const response = await fetch(`${API_BASE}${path}`, { ...init, headers });
  const body = await readApiResponse<T>(response);
  if (!response.ok || body.code !== 0) {
    throw new Error(body.detail || body.message || `${response.status} ${response.statusText}`);
  }
  return body.data;
}

async function readApiResponse<T>(response: Response): Promise<ApiResponse<T> & { detail?: string }> {
  const text = await response.text();
  if (!text.trim()) {
    throw new Error(response.ok ? "接口返回为空" : `服务暂时不可用（${response.status}）`);
  }
  try {
    return JSON.parse(text) as ApiResponse<T> & { detail?: string };
  } catch {
    throw new Error(response.ok ? "接口返回格式不正确" : `服务暂时不可用（${response.status}）`);
  }
}

async function download(path: string, filename: string) {
  const headers = new Headers();
  const token = getToken();
  if (token) headers.set("Authorization", `Bearer ${token}`);
  const response = await fetch(`${API_BASE}${path}`, { headers });
  if (!response.ok) throw new Error("导出失败");
  const blob = await response.blob();
  const url = window.URL.createObjectURL(blob);
  const anchor = document.createElement("a");
  anchor.href = url;
  anchor.download = filename;
  anchor.click();
  window.URL.revokeObjectURL(url);
}

async function upload<T>(path: string, formData: FormData): Promise<T> {
  const headers = new Headers();
  const token = getToken();
  if (token) headers.set("Authorization", `Bearer ${token}`);
  const response = await fetch(`${API_BASE}${path}`, { method: "POST", body: formData, headers });
  const body = await readApiResponse<T>(response);
  if (!response.ok || body.code !== 0) {
    throw new Error(body.message || body.detail || `${response.status} ${response.statusText}`);
  }
  return body.data;
}

function queryString(query: object) {
  const params = new URLSearchParams();
  Object.entries(query).forEach(([key, value]) => {
    if (value !== undefined && value !== null && value !== "") params.set(key, String(value));
  });
  const text = params.toString();
  return text ? `?${text}` : "";
}

export const api = {
  login: (username: string, password: string) =>
    request<{ token: string; admin: AdminProfile }>("/admin/login", {
      method: "POST",
      body: JSON.stringify({ username, password }),
    }),
  logout: () => request<null>("/admin/logout", { method: "POST", body: "{}" }),
  profile: () => request<AdminProfile>("/admin/profile"),
  permissionTree: () => request<PermissionNode[]>("/admin/permission-tree"),
  administrators: () => request<ManagedAdmin[]>("/admin/administrator/list"),
  createAdministrator: (payload: Record<string, unknown>) => request<ManagedAdmin>("/admin/administrator", { method: "POST", body: JSON.stringify(payload) }),
  updateAdministrator: (id: number, payload: Record<string, unknown>) => request<ManagedAdmin>(`/admin/administrator/${id}`, { method: "PUT", body: JSON.stringify(payload) }),
  deleteAdministrator: (id: number) => request<null>(`/admin/administrator/${id}`, { method: "DELETE" }),
  changeAdminPassword: (payload: { currentPassword: string; newPassword: string }) => request<null>("/admin/password", { method: "POST", body: JSON.stringify(payload) }),
  dashboard: (start?: string, end?: string) => {
    const params = new URLSearchParams();
    if (start) params.set("start", start);
    if (end) params.set("end", end);
    const qs = params.toString();
    return request<DashboardStats>(`/admin/dashboard${qs ? "?" + qs : ""}`);
  },
  peakTraffic: (grain: TrafficGrain) =>
    request<PeakTrafficResult>(`/admin/dashboard/traffic${queryString({ grain })}`),
  users: (query: { keyword?: string; planId?: number; entitlementStatus?: string; page?: number; pageSize?: number } = {}) => request<PageResult<AdminUser>>(`/admin/user/list${queryString(query)}`),
  userDetail: (id: number) => request<AdminUserDetail>(`/admin/user/${id}/detail`),
  userTopics: (id: number, query: { keyword?: string; page?: number; pageSize?: number } = {}) =>
    request<PageResult<TopicSessionRecord>>(`/admin/user/${id}/topics${queryString(query)}`),
  userReports: (id: number, limit = 20) => request<PeriodicReportRecord[]>(`/admin/user/${id}/reports${queryString({ limit })}`),
  generateUserReport: (id: number, payload: { reportType: string; periodStart?: string | null; periodEnd?: string | null }) =>
    request<PeriodicReportRecord>(`/admin/user/${id}/reports/generate`, { method: "POST", body: JSON.stringify(payload) }),
  retryTopicSettlement: (userId: number, topicId: number) =>
    request<TopicSummaryRecord>(`/admin/user/${userId}/topic/${topicId}/settlement/retry`, { method: "POST", body: "{}" }),
  createUser: (payload: Record<string, unknown>) =>
    request<AdminUser>("/admin/user", { method: "POST", body: JSON.stringify(payload) }),
  importUsers: (students: Record<string, unknown>[]) =>
    request<UserImportResult>("/admin/user/import", { method: "POST", body: JSON.stringify({ students }) }),
  downloadStudentTemplate: () => download("/admin/user/import/template", "学员导入模板.xlsx"),
  importUsersExcel: (file: File) => {
    const formData = new FormData();
    formData.append("file", file);
    return upload<UserImportResult>("/admin/user/import/excel", formData);
  },
  updateUser: (id: number, payload: Record<string, unknown>) =>
    request<AdminUser>(`/admin/user/${id}`, { method: "PUT", body: JSON.stringify(payload) }),
  deleteUser: (id: number) => request<null>(`/admin/user/${id}`, { method: "DELETE" }),
  entitlementPlans: (includeDisabled = true) =>
    request<EntitlementPlan[]>(`/admin/entitlement/plan/list${queryString({ includeDisabled })}`),
  createEntitlementPlan: (payload: Record<string, unknown>) =>
    request<EntitlementPlan>("/admin/entitlement/plan", { method: "POST", body: JSON.stringify(payload) }),
  updateEntitlementPlan: (id: number, payload: Record<string, unknown>) =>
    request<EntitlementPlan>(`/admin/entitlement/plan/${id}`, { method: "PUT", body: JSON.stringify(payload) }),
  assignUserEntitlement: (userId: number, payload: { planId: number; effectiveAt?: string | null; expiredAt?: string | null; remark?: string | null }) =>
    request<UserEntitlementSummary>(`/admin/user/${userId}/entitlement`, { method: "POST", body: JSON.stringify(payload) }),
  renewUserEntitlement: (userId: number, payload: { extensionDays: number; idempotencyKey: string; remark?: string | null }) =>
    request<UserEntitlementSummary>(`/admin/user/${userId}/entitlement/renew`, { method: "POST", body: JSON.stringify(payload) }),
  batchRenewUserEntitlement: (payload: { userIds: number[]; extensionDays: number; idempotencyKey: string; remark?: string | null }) =>
    request<EntitlementBatchRenewResult>("/admin/user/entitlement/batch-renew", { method: "POST", body: JSON.stringify(payload) }),
  knowledge: (query: Record<string, unknown> = {}) => request<PageResult<KnowledgeItem>>(`/admin/knowledge/list${queryString(query)}`),
  knowledgeOptions: () => request<KnowledgeItem[]>("/admin/knowledge/options"),
  resolveKnowledgeNode: (nodeId: string) => request<{ nodeId: string; spaceId: string; sourceTitle: string; name: string; remark: string }>("/admin/knowledge/resolve-node", { method: "POST", body: JSON.stringify({ nodeId }) }),
  createKnowledge: (payload: Record<string, unknown>) =>
    request<KnowledgeItem>("/admin/knowledge", { method: "POST", body: JSON.stringify(payload) }),
  updateKnowledge: (id: number, payload: Record<string, unknown>) =>
    request<KnowledgeItem>(`/admin/knowledge/${id}`, { method: "PUT", body: JSON.stringify(payload) }),
  updateKnowledgeMetadata: (id: number, payload: { name: string; knowledgeType: string }) =>
    request<KnowledgeItem>(`/admin/knowledge/${id}/metadata`, { method: "PATCH", body: JSON.stringify(payload) }),
  batchUpdateKnowledgeMetadata: (payload: { knowledgeIds: number[]; knowledgeType?: string }) =>
    request<KnowledgeBatchUpdateResult>("/admin/knowledge/batch/metadata", { method: "PATCH", body: JSON.stringify(payload) }),
  batchSyncKnowledge: (knowledgeIds: number[]) =>
    request<KnowledgeBatchSyncResult>("/admin/knowledge/batch/sync", {
      method: "POST",
      body: JSON.stringify({ knowledgeIds }),
    }),
  deleteKnowledge: (id: number) => request<null>(`/admin/knowledge/${id}`, { method: "DELETE" }),
  importKnowledgeFromSpace: (body: { node_token: string }) =>
    request<{ imported: number; skipped: number; id: number; name: string }>(
      "/admin/knowledge/import",
      { method: "POST", body: JSON.stringify(body) },
    ),
  knowledgeDetail: (id: number) => request<KnowledgeDetail>(`/admin/knowledge/${id}/detail`),
  knowledgeContentSearch: (query: { keyword: string; includeClosed?: boolean; page?: number; pageSize?: number }) =>
    request<PageResult<KnowledgeContentSearchItem>>(`/admin/knowledge/content-search${queryString(query)}`),
  knowledgeVersionContent: (versionId: number) => request<KnowledgeVersionContent>(`/admin/knowledge/version/${versionId}/content`),
  knowledgeSyncJobs: (id: number) => request<KnowledgeSyncJob[]>(`/admin/knowledge/${id}/sync-jobs`),
  syncKnowledge: (id: number) =>
    request<KnowledgeSyncJob>(`/admin/knowledge/${id}/sync`, { method: "POST" }),
  setKnowledgeOpen: (id: number, open: boolean) =>
    request<KnowledgeItem>(`/admin/knowledge/${id}/open-status`, { method: "PUT", body: JSON.stringify({ open }) }),
  setKnowledgeLifecycle: (id: number, status: "active" | "archived") =>
    request<KnowledgeItem>(`/admin/knowledge/${id}/lifecycle`, { method: "PUT", body: JSON.stringify({ status }) }),
  migrationSummary: () => request<MigrationSummary>("/admin/knowledge-migration/summary"),
  runKnowledgeMigration: (knowledgeId?: number) =>
    request<{ total: number; success: number; results: Record<string, unknown>[] }>(`/admin/knowledge-migration/run${knowledgeId ? `?knowledgeId=${knowledgeId}` : ""}`, { method: "POST", body: "{}" }),
  prompt: () => request<PromptDetail>("/admin/prompt"),
  savePrompt: (promptContent: string) =>
    request<PromptDetail>("/admin/prompt", { method: "PUT", body: JSON.stringify({ promptContent }) }),
  resetPrompt: () => request<PromptDetail>("/admin/prompt/reset", { method: "POST", body: "{}" }),
  promptHistory: (query: { page?: number; pageSize?: number } = {}) =>
    request<PageResult<PromptHistoryItem>>(`/admin/prompt/history${queryString(query)}`),
  promptHistoryDetail: (id: number) => request<PromptDetail>(`/admin/prompt/history/${id}`),
  restorePrompt: (id: number) => request<PromptDetail>(`/admin/prompt/history/${id}/restore`, { method: "POST", body: "{}" }),
  contentGenerationConfig: (configType: ContentGenerationType) =>
    request<ContentGenerationConfigDetail>(`/admin/content-generation/config/${configType}`),
  saveContentGenerationConfig: (
    configType: ContentGenerationType,
    payload: { templateContent: string; instructionContent: string },
  ) => request<ContentGenerationConfigDetail>(`/admin/content-generation/config/${configType}`, {
    method: "PUT",
    body: JSON.stringify(payload),
  }),
  resetContentGenerationConfig: (configType: ContentGenerationType) =>
    request<ContentGenerationConfigDetail>(`/admin/content-generation/config/${configType}/reset`, { method: "POST", body: "{}" }),
  contentGenerationHistory: (configType: ContentGenerationType, query: { page?: number; pageSize?: number } = {}) =>
    request<PageResult<ContentGenerationHistoryItem>>(`/admin/content-generation/config/${configType}/history${queryString(query)}`),
  contentGenerationHistoryDetail: (configType: ContentGenerationType, id: number) =>
    request<ContentGenerationConfigDetail>(`/admin/content-generation/config/${configType}/history/${id}`),
  restoreContentGenerationConfig: (configType: ContentGenerationType, id: number) =>
    request<ContentGenerationConfigDetail>(`/admin/content-generation/config/${configType}/history/${id}/restore`, { method: "POST", body: "{}" }),
  previewContentGeneration: (payload: { configType: ContentGenerationType; templateContent: string }) =>
    request<{ content: string }>("/admin/content-generation/preview", { method: "POST", body: JSON.stringify(payload) }),
  testContentGeneration: (payload: {
    configType: ContentGenerationType;
    templateContent: string;
    instructionContent: string;
    sampleText: string;
  }) => request<{ content: string; usedFallback: boolean }>("/admin/content-generation/test", {
    method: "POST",
    body: JSON.stringify(payload),
  }),
  debugAgent: (payload: Record<string, unknown>) =>
    request<AgentDebugResult>("/admin/agent/debug", { method: "POST", body: JSON.stringify(payload) }),
  agentRuntimeConfig: () => request<AgentRuntimeConfig>("/admin/agent/runtime-config"),
  saveAgentRuntimeConfig: (payload: AgentGenerationConfig) =>
    request<AgentRuntimeConfig>("/admin/agent/runtime-config", { method: "PUT", body: JSON.stringify(payload) }),
  models: () => request<ModelItem[]>("/admin/model/list"),
  createModel: (payload: Record<string, unknown>) =>
    request<ModelItem>("/admin/model", { method: "POST", body: JSON.stringify(payload) }),
  updateModel: (id: number, payload: Record<string, unknown>) =>
    request<ModelItem>(`/admin/model/${id}`, { method: "PUT", body: JSON.stringify(payload) }),
  setModelAvailability: (modelId: number, enabled: number) =>
    request<null>("/admin/model/enable", { method: "POST", body: JSON.stringify({ modelId, enabled }) }),
  setDefaultModel: (modelId: number) =>
    request<null>("/admin/model/default", { method: "POST", body: JSON.stringify({ modelId }) }),
  deleteModel: (modelId: number) =>
    request<null>(`/admin/model/${modelId}`, { method: "DELETE" }),
  testModel: (modelId: number) =>
    request<{ ok: boolean; message: string; answer: string }>(`/admin/model/${modelId}/test`, {
      method: "POST",
      body: "{}",
    }),
  configs: () => request<SystemConfigItem[]>("/admin/config"),
  saveConfig: (payload: Record<string, unknown>) =>
    request<SystemConfigItem>("/admin/config", { method: "PUT", body: JSON.stringify(payload) }),
  ssoConfig: () => request<{ userClientUrl: string }>("/admin/sso/config"),
  saveSsoConfig: (userClientUrl: string) =>
    request<{ userClientUrl: string }>("/admin/sso/config", {
      method: "PUT",
      body: JSON.stringify({ userClientUrl }),
    }),
  ssoClients: () => request<SsoClientItem[]>("/admin/sso/client/list"),
  createSsoClient: (payload: { appId: string; name: string; redirectUris: string[]; allowAutoRegister: boolean; defaultEntitlementPlanId?: number | null; status: number }) =>
    request<SsoClientItem>("/admin/sso/client", { method: "POST", body: JSON.stringify(payload) }),
  updateSsoClient: (id: number, payload: { name: string; redirectUris: string[]; allowAutoRegister: boolean; defaultEntitlementPlanId?: number | null; status: number }) =>
    request<SsoClientItem>(`/admin/sso/client/${id}`, { method: "PUT", body: JSON.stringify(payload) }),
  rotateSsoClientSecret: (id: number) =>
    request<{ clientId: number; clientSecret: string }>(`/admin/sso/client/${id}/secret/rotate`, {
      method: "POST",
      body: "{}",
    }),
  ssoIdentities: (query: { clientId?: number; keyword?: string; page?: number; pageSize?: number } = {}) =>
    request<PageResult<SsoIdentityItem>>(`/admin/sso/identity/list${queryString(query)}`),
  unlinkSsoIdentity: (id: number) => request<null>(`/admin/sso/identity/${id}`, { method: "DELETE" }),
  ssoAudits: (query: { clientId?: number; auditStatus?: string; page?: number; pageSize?: number } = {}) =>
    request<PageResult<SsoAuditItem>>(`/admin/sso/audit/list${queryString(query)}`),
  chats: (query: ChatRecordQuery = {}) => request<PageResult<ChatRecord>>(`/admin/chat/list${queryString(query)}`),
  chatDetail: (sessionId: number, query: { messagePage?: number; messagePageSize?: number } = {}) =>
    request<ChatDetail>(`/admin/chat/${sessionId}${queryString(query)}`),
  chatMessages: (sessionId: number, query: { page?: number; pageSize?: number } = {}) =>
    request<PageResult<ChatMessageRecord>>(`/admin/chat/${sessionId}/messages${queryString(query)}`),
  exportChats: (query: ChatRecordQuery = {}) => download(`/admin/chat/export${queryString(query)}`, "chat_records.csv"),
  aiLogs: (query: { sessionId?: number; userId?: number; status?: string; page?: number; pageSize?: number } = {}) =>
    request<PageResult<AiLogRecord>>(`/admin/ai-log/list${queryString(query)}`),
  aiLogDetail: (id: number) => request<AiLogRecord>(`/admin/ai-log/${id}`),
  operationLogs: (query: { module?: string; page?: number; pageSize?: number } = {}) => request<PageResult<Record<string, unknown>>>(`/admin/log/list${queryString(query)}`),
  questionInsights: (query: { dateFrom?: string; dateTo?: string; minCount?: number; maxMessages?: number; page?: number; pageSize?: number } = {}) =>
    request<QuestionInsightSummary>(`/admin/question-insights/summary${queryString(query)}`),
  refreshQuestionInsights: (query: { dateFrom?: string; dateTo?: string; maxMessages?: number } = {}) =>
    request<QuestionInsightRefreshResult>(`/admin/question-insights/refresh${queryString(query)}`, {
      method: "POST",
    }),
  retrievalLogs: (query: { page?: number; pageSize?: number } = {}) => request<PageResult<RetrievalLogItem>>(`/admin/retrieval-log/list${queryString(query)}`),
  estimateRetrievalCleanup: (before: string) => request<{ before: string; estimatedCount: number }>("/admin/retrieval-log/cleanup/estimate", { method: "POST", body: JSON.stringify({ before }) }),
  cleanupRetrievalLogs: (before: string) => request<{ before: string; deleted: number }>("/admin/retrieval-log/cleanup", { method: "POST", body: JSON.stringify({ before }) }),
  retrievalRetention: () => request<{ enabled: boolean; retentionDays: number | null; lastRunAt: string | null; lastResult: string | null }>("/admin/retrieval-log/retention"),
  saveRetrievalRetention: (retentionDays: number | null) => request<{ enabled: boolean; retentionDays: number | null }>("/admin/retrieval-log/retention", { method: "PUT", body: JSON.stringify({ retentionDays }) }),
  storageStats: (refresh = false) => request<Record<string, any>>(`/admin/dashboard/storage${refresh ? "?refresh=true" : ""}`),
  retrievalLogDetail: (id: number) => request<Record<string, unknown>>(`/admin/retrieval-log/${id}`),
  attentionList: (query: { page?: number; pageSize?: number } = {}) => request<PageResult<AttentionItem>>(`/admin/attention/list${queryString(query)}`),
  updateAttention: (id: number, status: string, note?: string) =>
    request<AttentionItem>(`/admin/attention/${id}`, { method: "PUT", body: JSON.stringify({ status, note }) }),
  deleteAttention: (id: number) => request<null>(`/admin/attention/${id}`, { method: "DELETE" }),
  clearFeishuCache: () =>
    request<{ cleared: number; message: string }>("/admin/feishu/cache/clear", { method: "POST", body: "{}" }),
  feedbackList: (query: { readStatus?: string; page?: number; pageSize?: number } = {}) => request<PageResult<import("../types/api").FeedbackItem>>(`/feedback/admin/list${queryString(query)}`),
  feedbackDetail: (id: number) => request<import("../types/api").FeedbackDetail>(`/feedback/admin/${id}`),
  deleteFeedback: (id: number) => request<null>(`/feedback/admin/${id}`, { method: "DELETE" }),
};

export async function streamDebugAgent(
  payload: Record<string, unknown>,
  onChunk: (chunk: string) => void,
  onReasoning: (chunk: string) => void,
  onStatus: (status: { message: string; reasoningVisible: boolean }) => void,
  onComplete: (result: AgentDebugStreamComplete) => void,
  signal?: AbortSignal,
) {
  const token = getToken();
  const response = await fetch(`${API_BASE}/admin/agent/debug/stream`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
    },
    body: JSON.stringify(payload),
    signal,
  });
  if (!response.ok || !response.body) {
    const body = await readApiResponse<unknown>(response);
    throw new Error(body.detail || body.message || "Agent 调试连接失败");
  }
  const reader = response.body.getReader();
  const decoder = new TextDecoder("utf-8");
  let buffer = "";
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    buffer += decoder.decode(value, { stream: true });
    const events = buffer.split(/\r?\n\r?\n/);
    buffer = events.pop() ?? "";
    for (const event of events) {
      const dataLines = event.split(/\r?\n/).filter((line) => line.startsWith("data:"));
      if (!dataLines.length) continue;
      const data = dataLines.map((line) => line.slice(5).trimStart()).join("\n").trim();
      if (data === "[DONE]") return;
      const parsed = JSON.parse(data) as AgentDebugStreamComplete & {
        type?: string;
        content?: string;
        reasoningVisible?: boolean;
      };
      if (parsed.type === "error") throw new Error(parsed.message || "Agent 调试失败");
      if (parsed.type === "content" && parsed.content) onChunk(parsed.content);
      if (parsed.type === "reasoning" && parsed.content) onReasoning(parsed.content);
      if (parsed.type === "status") {
        onStatus({ message: parsed.message || "思考中", reasoningVisible: Boolean(parsed.reasoningVisible) });
      }
      if (parsed.type === "complete") onComplete(parsed);
    }
  }
}
