import { api } from "@/lib/api";

export interface CodeKnowledgeBase {
  id: number;
  name: string;
  project_path?: string | null;
  vector_path: string;
  metadata_path: string;
  graph_path: string;
  status: string;
  metadata_summary?: Record<string, unknown> | null;
  created_at: string;
  updated_at: string;
}

export interface CreateCodeKnowledgeBaseRequest {
  name: string;
  project_path?: string;
  vector_path: string;
  metadata_path: string;
  graph_path: string;
}

export interface CodeKnowledgeBaseUploadResponse {
  id: number;
  status: string;
}

export interface CodeQuestionResponse {
  answer: string;
  evidence: Array<Record<string, any>>;
  raw_response?: string | null;
}

export interface CreateConsistencyJobRequest {
  srs_extraction_id: number;
  code_kb_id: number;
  requirement_uids?: string[];
  top_k: number;
  max_call_hops: number;
  min_similarity: number;
  use_llm: boolean;
}

export interface ConsistencyJob {
  id: number;
  srs_extraction_id: number;
  code_kb_id: number;
  status: "pending" | "processing" | "completed" | "failed";
  total_requirements: number;
  completed_requirements: number;
  output_summary?: Record<string, unknown> | null;
  error_message?: string | null;
  started_at?: string | null;
  completed_at?: string | null;
  created_at: string;
  updated_at: string;
}

export interface ConsistencyResult {
  id: number;
  job_id: number;
  requirement_uid: string;
  verdict: "implemented" | "partial" | "missing" | "conflict" | "uncertain";
  coverage_score: number;
  confidence: number;
  matched_functions: Array<Record<string, any>>;
  covered_points: string[];
  missing_points: string[];
  conflict_points: string[];
  call_chain_evidence: string[];
  suggestion?: string | null;
  raw_judgment?: Record<string, unknown> | null;
  created_at: string;
  updated_at: string;
}

export interface AutoConsistencyJobStatus {
  job_id: number;
  status: "pending" | "processing" | "completed" | "failed";
  error_message?: string | null;
  current_step?: string | null;
  srs_extraction_id?: number | null;
  code_kb_id?: number | null;
  consistency_job_id?: number | null;
  created_at: string;
  updated_at: string;
}

export const listCodeKnowledgeBases = async (): Promise<CodeKnowledgeBase[]> => {
  return api.get("/api/consistency/code-kbs") as Promise<CodeKnowledgeBase[]>;
};

export const createCodeKnowledgeBase = async (
  payload: CreateCodeKnowledgeBaseRequest
): Promise<CodeKnowledgeBase> => {
  return api.post("/api/consistency/code-kbs", payload) as Promise<CodeKnowledgeBase>;
};

export const uploadCodeKnowledgeBase = async (
  name: string,
  files: File[],
  useSemantic = true
): Promise<CodeKnowledgeBaseUploadResponse> => {
  const formData = new FormData();
  formData.append("name", name);
  formData.append("use_semantic", String(useSemantic));
  files.forEach((file) => formData.append("files", file));
  return api.post("/api/consistency/code-kbs/upload", formData) as Promise<CodeKnowledgeBaseUploadResponse>;
};

export const deleteCodeKnowledgeBase = async (id: number): Promise<void> => {
  await api.delete(`/api/consistency/code-kbs/${id}`);
};

export const askCodeKnowledgeBase = async (
  id: number,
  question: string,
  topK = 6,
  useLlm = true
): Promise<CodeQuestionResponse> => {
  return api.post(`/api/consistency/code-kbs/${id}/ask`, {
    question,
    top_k: topK,
    use_llm: useLlm,
  }) as Promise<CodeQuestionResponse>;
};

export const createConsistencyJob = async (
  payload: CreateConsistencyJobRequest
): Promise<{ job_id: number; status: string }> => {
  return api.post("/api/consistency/jobs", payload) as Promise<{
    job_id: number;
    status: string;
  }>;
};

export const listConsistencyJobs = async (): Promise<ConsistencyJob[]> => {
  return api.get("/api/consistency/jobs") as Promise<ConsistencyJob[]>;
};

export const getConsistencyJob = async (id: number): Promise<ConsistencyJob> => {
  return api.get(`/api/consistency/jobs/${id}`) as Promise<ConsistencyJob>;
};

export const getConsistencyResults = async (
  id: number
): Promise<ConsistencyResult[]> => {
  return api.get(`/api/consistency/jobs/${id}/results`) as Promise<ConsistencyResult[]>;
};

export const createAutoConsistencyJob = async (
  requirementFile: File,
  codeFiles: File[],
  options: {
    codeKbName: string;
    topK: number;
    maxCallHops: number;
    minSimilarity: number;
    useLlm: boolean;
    useSemantic: boolean;
  }
): Promise<{ job_id: number; status: string }> => {
  const formData = new FormData();
  formData.append("requirement_file", requirementFile);
  codeFiles.forEach((file) => formData.append("code_files", file));
  formData.append("code_kb_name", options.codeKbName);
  formData.append("top_k", String(options.topK));
  formData.append("max_call_hops", String(options.maxCallHops));
  formData.append("min_similarity", String(options.minSimilarity));
  formData.append("use_llm", String(options.useLlm));
  formData.append("use_semantic", String(options.useSemantic));
  return api.post("/api/consistency/auto-jobs", formData) as Promise<{
    job_id: number;
    status: string;
  }>;
};

export const getAutoConsistencyJob = async (
  id: number
): Promise<AutoConsistencyJobStatus> => {
  return api.get(`/api/consistency/auto-jobs/${id}`) as Promise<AutoConsistencyJobStatus>;
};

export const downloadConsistencyExport = async (
  jobId: number,
  format: "json" | "markdown" | "xlsx"
) => {
  let token = "";
  if (typeof window !== "undefined") {
    token = localStorage.getItem("token") || "";
  }
  const response = await fetch(`/api/consistency/jobs/${jobId}/export?format=${format}`, {
    headers: token ? { Authorization: `Bearer ${token}` } : {},
  });
  if (!response.ok) {
    const errorData = await response.json().catch(() => ({}));
    throw new Error(errorData.detail || "导出失败");
  }
  const blob = await response.blob();
  const suffix = format === "markdown" ? "md" : format;
  const url = window.URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = `consistency-job-${jobId}.${suffix}`;
  link.click();
  window.URL.revokeObjectURL(url);
};
