import { API_BASE, request } from "./core";

// ── Types ────────────────────────────────────────────────────────────────────

export type OCRStatus = "pending" | "done" | "failed" | "skipped" | "disabled";

export type SearchMatchField =
  | "subject"
  | "body"
  | "attachment_text"
  | "attachment_names"
  | "from_addr"
  | "to_addr";

export interface SearchHit {
  id: string;
  score: number;
  from?: string;
  to?: string;
  subject?: string;
  date?: string;
  size?: number;
  has_attachments?: boolean;
  thread_id?: string;
  thread_size?: number;
  // PROJ-44: Manticore snippet (with <b>...</b> highlights) and source field
  snippet?: string;
  match_field?: SearchMatchField;
}

export interface ThreadMail {
  id: string;
  from?: string;
  to?: string;
  subject: string;
  date?: string;
  size: number;
}

export interface ThreadResponse {
  thread_id: string;
  total: number;
  mails: ThreadMail[];
}

export interface SearchResponse {
  total: number;
  hits: SearchHit[];
}

export interface MailAttachment {
  index: number;
  filename: string;
  content_type: string;
  size: number;
}

export interface MailDetail {
  id: string;
  from: string;
  to: string;
  cc?: string;
  subject: string;
  date: string;
  size: number;
  body_html?: string;
  body_plain?: string;
  raw_headers: string;
  attachments: MailAttachment[];
  verify_ok: boolean | null;
  verified_at: string | null;
  thread_id?: string;
  // PROJ-44: OCR status and extracted-text length
  ocr_status?: OCRStatus;
  ocr_chars?: number;
  // PROJ-51: retention lock + its source for auditor traceability.
  // retain_until_source: "rule:<id>" | "tenant_default" | "global_default" | "min_retention"
  retain_until?: string | null;
  retain_until_source?: string | null;
}

export interface ImapFolder {
  name: string;
  excluded: boolean;
  reason?: string;
}

export interface ImapAccount {
  id: number;
  owner: string;
  name: string;
  host: string;
  port: number;
  tls: string;
  username: string;
  excluded_folders: string[];
  status: string;
  error_msg: string;
  last_import_at?: string;
  last_import_count: number;
  progress_current: number;
  progress_total: number;
  created_at: string;
  // PROJ-8: Auto-sync fields
  sync_interval_min: number;
  last_sync_at?: string;
  last_sync_count: number;
  sync_running: boolean;
  sync_status: string;
  sync_error_msg: string;
}

export interface ImapTestResult {
  ok: boolean;
  folders?: ImapFolder[];
  error?: string;
}

export interface Pop3Account {
  id: number;
  owner: string;
  name: string;
  host: string;
  port: number;
  tls: string;
  tls_skip_verify: boolean;
  username: string;
  status: string;
  error_msg: string;
  last_import_at?: string;
  last_import_count: number;
  progress_current: number;
  progress_total: number;
  created_at: string;
}

export interface Pop3TestResult {
  ok: boolean;
  message: string;
  message_count?: number;
  total_size_bytes?: number;
}

export interface UploadJob {
  id: string;
  status: "running" | "done" | "error";
  total: number;
  imported: number;
  skipped: number;
  errors: number;
  error_msg?: string;
}

// ── Search ────────────────────────────────────────────────────────────────────

export async function searchEmails(params: {
  q?: string;
  from?: string;
  to?: string;
  date_from?: string;
  date_to?: string;
  sort?: string;
  has_attachment?: boolean;
  page?: number;
  page_size?: number;
}): Promise<SearchResponse> {
  const sp = new URLSearchParams();
  if (params.q) sp.set("q", params.q);
  if (params.from) sp.set("from", params.from);
  if (params.to) sp.set("to", params.to);
  if (params.date_from) sp.set("date_from", params.date_from);
  if (params.date_to) sp.set("date_to", params.date_to);
  if (params.sort) sp.set("sort", params.sort);
  if (params.has_attachment !== undefined) sp.set("has_attachment", String(params.has_attachment));
  if (params.page) sp.set("page", String(params.page));
  if (params.page_size) sp.set("page_size", String(params.page_size));
  return request<SearchResponse>(`/api/search?${sp.toString()}`);
}

// ── Mail detail ───────────────────────────────────────────────────────────────

export async function getMail(id: string): Promise<MailDetail> {
  return request<MailDetail>(`/api/mails/${id}`);
}

export async function downloadMailAttachment(
  id: string,
  index: number
): Promise<{ blob: Blob; filename: string }> {
  const res = await fetch(`${API_BASE}/api/mails/${id}/attachments/${index}`, {
    credentials: "include",
  });
  if (!res.ok) throw new Error(`Download fehlgeschlagen: ${res.status}`);
  const disposition = res.headers.get("Content-Disposition") || "";
  const match = disposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
  const filename = match ? match[1].replace(/['"]/g, "") : `anhang-${index}`;
  return { blob: await res.blob(), filename };
}

export async function downloadMailRaw(
  id: string
): Promise<{ blob: Blob; filename: string }> {
  const res = await fetch(`${API_BASE}/api/mails/${id}/raw`, {
    credentials: "include",
  });
  if (!res.ok) throw new Error(`Download fehlgeschlagen: ${res.status}`);
  return { blob: await res.blob(), filename: `${id}.eml` };
}

// ── OCR text ──────────────────────────────────────────────────────────────────

/** Direct URL of the OCR-text endpoint. Browser uses cookie auth automatically. */
export function getOCRTextDownloadURL(mailId: string): string {
  return `${API_BASE}/api/mails/${mailId}/ocr-text`;
}

export type OCRDownloadResult =
  | { kind: "ok"; blob: Blob; filename: string }
  | { kind: "pending" }
  | { kind: "not_available" };

/**
 * Fetch the OCR text. Handles the 202 (pending) and 404 (not available)
 * cases gracefully so the UI can show different feedback.
 */
export async function downloadMailOCRText(
  id: string
): Promise<OCRDownloadResult> {
  const res = await fetch(`${API_BASE}/api/mails/${id}/ocr-text`, {
    credentials: "include",
  });
  if (res.status === 202) return { kind: "pending" };
  if (res.status === 404) return { kind: "not_available" };
  if (!res.ok) throw new Error(`Download fehlgeschlagen: ${res.status}`);
  const cd = res.headers.get("Content-Disposition") || "";
  const match = cd.match(/filename="([^"]+)"/);
  const filename = match ? match[1] : `${id}.ocr.txt`;
  return { kind: "ok", blob: await res.blob(), filename };
}

// ── IMAP ──────────────────────────────────────────────────────────────────────

export async function getImapAccounts(): Promise<ImapAccount[]> {
  return request<ImapAccount[]>("/api/imap");
}

export async function createImapAccount(data: {
  name: string;
  host: string;
  port: number;
  tls: string;
  username: string;
  password: string;
  excluded_folders: string[];
}): Promise<ImapAccount> {
  return request<ImapAccount>("/api/imap", {
    method: "POST",
    body: JSON.stringify(data),
  });
}

export async function deleteImapAccount(id: number): Promise<void> {
  await request<void>(`/api/imap/${id}`, { method: "DELETE" });
}

export async function testImapConnection(data: {
  host: string;
  port: number;
  tls: string;
  username: string;
  password: string;
}): Promise<ImapTestResult> {
  return request<ImapTestResult>("/api/imap/test", {
    method: "POST",
    body: JSON.stringify(data),
  });
}

export async function startImapImport(id: number): Promise<ImapAccount> {
  return request<ImapAccount>(`/api/imap/${id}/import`, { method: "POST" });
}

export async function getImapProgress(id: number): Promise<ImapAccount> {
  return request<ImapAccount>(`/api/imap/${id}/progress`);
}

export async function triggerImapSync(id: number): Promise<ImapAccount> {
  return request<ImapAccount>(`/api/imap/${id}/sync`, { method: "POST" });
}

export async function updateImapInterval(id: number, intervalMin: number): Promise<ImapAccount> {
  return request<ImapAccount>(`/api/imap/${id}`, {
    method: "PATCH",
    body: JSON.stringify({ sync_interval_min: intervalMin }),
  });
}

export async function updateImapAccount(
  id: number,
  data: { name: string; host: string; port: number; tls: string; username: string; password?: string }
): Promise<ImapAccount> {
  return request<ImapAccount>(`/api/imap/${id}`, {
    method: "PATCH",
    body: JSON.stringify(data),
  });
}

// ── POP3 ──────────────────────────────────────────────────────────────────────

export async function getPop3Accounts(): Promise<Pop3Account[]> {
  return request<Pop3Account[]>("/api/pop3");
}

export async function createPop3Account(data: {
  name: string;
  host: string;
  port: number;
  tls: string;
  tls_skip_verify: boolean;
  username: string;
  password: string;
}): Promise<Pop3Account> {
  return request<Pop3Account>("/api/pop3", {
    method: "POST",
    body: JSON.stringify(data),
  });
}

export async function deletePop3Account(id: number): Promise<void> {
  await request<void>(`/api/pop3/${id}`, { method: "DELETE" });
}

export async function testPop3Connection(data: {
  host: string;
  port: number;
  tls: string;
  tls_skip_verify: boolean;
  username: string;
  password: string;
}): Promise<Pop3TestResult> {
  return request<Pop3TestResult>("/api/pop3/test", {
    method: "POST",
    body: JSON.stringify(data),
  });
}

export async function startPop3Import(id: number): Promise<Pop3Account> {
  return request<Pop3Account>(`/api/pop3/${id}/import`, { method: "POST" });
}

export async function getPop3Progress(id: number): Promise<Pop3Account> {
  return request<Pop3Account>(`/api/pop3/${id}/progress`);
}

// ── eDiscovery Export ─────────────────────────────────────────────────────────

export async function exportEDiscovery(params: {
  case_name?: string;
  q?: string;
  from?: string;
  to?: string;
  date_from?: string;
  date_to?: string;
  has_attachment?: boolean;
}): Promise<{ blob: Blob; filename: string }> {
  const res = await fetch(`${API_BASE}/api/export/ediscovery`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    credentials: "include",
    body: JSON.stringify(params),
  });
  if (!res.ok) throw new Error(`eDiscovery Export fehlgeschlagen: ${res.status}`);
  const cd = res.headers.get("Content-Disposition") || "";
  const filename = cd.match(/filename="([^"]+)"/)?.[1] || "archivmail-export.zip";
  return { blob: await res.blob(), filename };
}

// ── Thread ────────────────────────────────────────────────────────────────────

export async function getThread(threadID: string): Promise<ThreadResponse> {
  return request<ThreadResponse>(`/api/threads/${encodeURIComponent(threadID)}`);
}

// ── Export ────────────────────────────────────────────────────────────────────

export async function exportMailPDF(id: string): Promise<{ blob: Blob; filename: string }> {
  const res = await fetch(`${API_BASE}/api/export/pdf/${id}`, {
    credentials: "include",
  });
  if (!res.ok) throw new Error("PDF export failed");
  const blob = await res.blob();
  const cd = res.headers.get("Content-Disposition") || "";
  const filename = cd.match(/filename="([^"]+)"/)?.[1] || `${id.slice(0, 16)}.pdf`;
  return { blob, filename };
}

export async function exportMailsZIP(ids: string[], attachments: boolean): Promise<{ blob: Blob }> {
  const res = await fetch(`${API_BASE}/api/export/zip`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    credentials: "include",
    body: JSON.stringify({ ids, attachments }),
  });
  if (!res.ok) throw new Error("ZIP export failed");
  return { blob: await res.blob() };
}

// ── Upload ────────────────────────────────────────────────────────────────────

export async function uploadMailFiles(files: File[]): Promise<{ job_id: string }> {
  const form = new FormData();
  for (const f of files) form.append("files", f);
  const res = await fetch(`${API_BASE}/api/admin/upload`, {
    method: "POST",
    credentials: "include",
    body: form,
  });
  if (!res.ok) {
    const body = await res.text();
    throw new Error(body || `Upload failed: ${res.status}`);
  }
  return res.json();
}

export async function getUploadProgress(jobID: string): Promise<UploadJob> {
  return request<UploadJob>(`/api/admin/upload/${jobID}/progress`);
}

export async function uploadMailFilesUser(files: File[]): Promise<{ job_id: string }> {
  const form = new FormData();
  for (const f of files) form.append("files", f);
  const res = await fetch(`${API_BASE}/api/upload`, {
    method: "POST",
    credentials: "include",
    body: form,
  });
  if (!res.ok) {
    const body = await res.text();
    throw new Error(body || `Upload failed: ${res.status}`);
  }
  return res.json();
}

export async function getUploadProgressUser(jobID: string): Promise<UploadJob> {
  return request<UploadJob>(`/api/upload/${jobID}/progress`);
}
