// @File: src/lib/moduleSyncApi.ts
// @Desc: Typed fetch wrappers for the universal "Fetch Data Toggle" system.
//        Mirrors the envelope conventions used by the other admin APIs:
//        JSON body, bearer token from localStorage, error detail parsed
//        into a single string message.
import { getToken } from "@/lib/auth";

// ---------- helpers ----------
function authHeaders(extra?: Record<string, string>): HeadersInit {
  const token = getToken();
  return {
    "Content-Type": "application/json",
    ...(token ? { Authorization: `Bearer ${token}` } : {}),
    ...(extra ?? {}),
  };
}

async function handle<T>(res: Response): Promise<T> {
  const raw = await res.text();
  let data: unknown = null;
  if (raw) {
    try {
      data = JSON.parse(raw);
    } catch {
      data = raw;
    }
  }
  if (!res.ok) {
    const detail =
      (data && typeof data === "object" && "detail" in (data as Record<string, unknown>)
        ? (data as { detail?: unknown }).detail
        : undefined) ?? res.statusText;
    const message =
      typeof detail === "string"
        ? detail
        : typeof detail === "object"
          ? JSON.stringify(detail)
          : String(detail ?? "Request failed");
    throw new Error(message);
  }
  return data as T;
}

const BASE = "/api/v1/admin/module-sync";

// ---------- types ----------
export type SyncType = "clients" | "accounts" | "domains";

export type SyncStatus = "ok" | "failed" | "skipped" | "never";

export interface ModuleSyncSettings {
  module_name: string;
  module_label: string;
  fetch_clients_enabled: boolean;
  fetch_accounts_enabled: boolean;
  fetch_domains_enabled: boolean;
  last_clients_sync: string | null;
  last_accounts_sync: string | null;
  last_domains_sync: string | null;
  clients_sync_status: SyncStatus;
  accounts_sync_status: SyncStatus;
  domains_sync_status: SyncStatus;
  clients_count: number;
  accounts_count: number;
  domains_count: number;
  domains_linked_count: number;
  domains_unlinked_count: number;
  last_error: string | null;
}

export interface ModuleSyncToggleUpdate {
  fetch_clients_enabled?: boolean;
  fetch_accounts_enabled?: boolean;
  fetch_domains_enabled?: boolean;
}

export interface ModuleSyncRunResult {
  module_name: string;
  sync_type: SyncType;
  status: SyncStatus;
  items_fetched: number;
  error_message: string | null;
  started_at: string;
  finished_at: string | null;
  duration_ms: number;
}

export interface ModuleSyncRunAllResult {
  module_name: string;
  runs: ModuleSyncRunResult[];
}

export interface ModuleSyncLogItem {
  id: number;
  module_name: string;
  sync_type: string;
  status: SyncStatus;
  items_fetched: number;
  error_message: string | null;
  triggered_by: string;
  actor_email: string | null;
  duration_ms: number;
  started_at: string;
  finished_at: string | null;
}

export interface ModuleSyncLogDetail extends ModuleSyncLogItem {
  raw_response: string | null;
}

export interface ModuleSyncLogList {
  items: ModuleSyncLogItem[];
  total: number;
}

export interface ModuleDiagnosticStep {
  step: string;
  ok: boolean;
  detail: string | null;
}

export interface ModuleDiagnosticsResult {
  module_name: string;
  ok: boolean;
  steps: ModuleDiagnosticStep[];
  message: string | null;
}

// ---------- endpoints ----------
export async function listModules(): Promise<ModuleSyncSettings[]> {
  const res = await fetch(`${BASE}/modules`, { headers: authHeaders() });
  return handle<ModuleSyncSettings[]>(res);
}

export async function getModule(moduleName: string): Promise<ModuleSyncSettings> {
  const res = await fetch(`${BASE}/modules/${moduleName}`, { headers: authHeaders() });
  return handle<ModuleSyncSettings>(res);
}

export async function updateToggles(
  moduleName: string,
  body: ModuleSyncToggleUpdate,
): Promise<ModuleSyncSettings> {
  const res = await fetch(`${BASE}/modules/${moduleName}`, {
    method: "PATCH",
    headers: authHeaders(),
    body: JSON.stringify(body),
  });
  return handle<ModuleSyncSettings>(res);
}

export async function fetchNow(
  moduleName: string,
  syncType: SyncType,
): Promise<ModuleSyncRunResult> {
  const res = await fetch(`${BASE}/modules/${moduleName}/fetch/${syncType}`, {
    method: "POST",
    headers: authHeaders(),
  });
  return handle<ModuleSyncRunResult>(res);
}

export async function fetchAllNow(moduleName: string): Promise<ModuleSyncRunAllResult> {
  const res = await fetch(`${BASE}/modules/${moduleName}/fetch-all`, {
    method: "POST",
    headers: authHeaders(),
  });
  return handle<ModuleSyncRunAllResult>(res);
}

export async function listLogs(params: {
  module_name?: string;
  sync_type?: string;
  status?: SyncStatus;
  limit?: number;
  offset?: number;
}): Promise<ModuleSyncLogList> {
  const qs = new URLSearchParams();
  Object.entries(params).forEach(([k, v]) => {
    if (v !== undefined && v !== null && v !== "") qs.set(k, String(v));
  });
  const res = await fetch(`${BASE}/logs?${qs.toString()}`, { headers: authHeaders() });
  return handle<ModuleSyncLogList>(res);
}

export async function getLog(id: number): Promise<ModuleSyncLogDetail> {
  const res = await fetch(`${BASE}/logs/${id}`, { headers: authHeaders() });
  return handle<ModuleSyncLogDetail>(res);
}

export async function runDiagnostics(moduleName: string): Promise<ModuleDiagnosticsResult> {
  const res = await fetch(`${BASE}/diagnostics/${moduleName}`, {
    method: "POST",
    headers: authHeaders(),
  });
  return handle<ModuleDiagnosticsResult>(res);
}