// app/src/lib/crmApi.ts
// CRM API client — canonical CRM routes
// Implements the frontend adapter layer from Doc 10 (TypeScript Module Spec)

import type {
  CrmContactListItem,
  CrmPerson,
  Client360Snapshot,
  CrmOpportunityCard,
  CrmTask,
  CrmLeadStageUpdate,
  KanbanColumn,
  ImportBatchSummary,
  ImportProposal,
  ImportReviewDecision,
  QdScoreEntry,
  OracleClientDataListItem,
  OracleClientDataDetail,
  OracleClientTimelineItem,
} from '@/types/crmTypes';
import { buildVelocityHeaders } from '@/lib/velocitySession';

const API_BASE = import.meta.env.VITE_API_BASE_URL ?? '';

function getAuthHeaders(): Record<string, string> {
  return Object.fromEntries(buildVelocityHeaders(undefined, false).entries());
}

async function apiFetch<T>(path: string, options?: RequestInit): Promise<T> {
  const res = await fetch(`${API_BASE}${path}`, {
    ...options,
    headers: {
      'Content-Type': 'application/json',
      ...getAuthHeaders(),
      ...(options?.headers ?? {}),
    },
  });
  if (!res.ok) {
    const err = await res.json().catch(() => ({ detail: res.statusText }));
    throw new Error(err.detail ?? `API error ${res.status}`);
  }
  return res.json() as Promise<T>;
}

// ── Contact List ──────────────────────────────────────────────────────────────

export async function fetchContacts(params: {
  search?: string;
  buyer_type?: string;
  status?: string;
  limit?: number;
  offset?: number;
}): Promise<{ contacts: CrmContactListItem[]; total: number; limit: number; offset: number }> {
  const qs = new URLSearchParams();
  if (params.search) qs.set('search', params.search);
  if (params.buyer_type) qs.set('buyer_type', params.buyer_type);
  if (params.status) qs.set('status', params.status);
  if (params.limit != null) qs.set('limit', String(params.limit));
  if (params.offset != null) qs.set('offset', String(params.offset));
  const res = await apiFetch<{ status: string; data: { contacts: CrmContactListItem[]; total: number; limit: number; offset: number } }>(
    `/api/crm/contacts?${qs}`
  );
  return res.data;
}

export async function fetchContact(personId: string): Promise<CrmPerson> {
  const res = await apiFetch<{ status: string; data: CrmPerson }>(`/api/crm/contacts/${personId}`);
  return res.data;
}

// ── Client 360 ────────────────────────────────────────────────────────────────

export async function fetchClient360(personId: string): Promise<Client360Snapshot> {
  const res = await apiFetch<{ status: string; data: Client360Snapshot }>(`/api/crm/client-360/${personId}`);
  return res.data;
}

// ── Opportunities ─────────────────────────────────────────────────────────────

export async function fetchOpportunities(params?: {
  stage?: string;
  limit?: number;
  offset?: number;
}): Promise<CrmOpportunityCard[]> {
  const qs = new URLSearchParams();
  if (params?.stage) qs.set('stage', params.stage);
  if (params?.limit != null) qs.set('limit', String(params.limit));
  if (params?.offset != null) qs.set('offset', String(params.offset));
  const res = await apiFetch<{ status: string; data: CrmOpportunityCard[] }>(`/api/crm/opportunities?${qs}`);
  return res.data;
}

export async function updateOpportunity(body: {
  opportunity_id: string;
  stage?: string;
  value?: number | null;
  probability?: number | null;
  expected_close_date?: string | null;
  next_action?: string | null;
  notes?: string | null;
}): Promise<CrmOpportunityCard> {
  const { opportunity_id, ...payload } = body;
  const res = await apiFetch<{ status: string; data: CrmOpportunityCard }>(`/api/crm/opportunities/${opportunity_id}`, {
    method: 'PATCH',
    body: JSON.stringify(payload),
  });
  return res.data;
}

// ── Tasks ─────────────────────────────────────────────────────────────────────

export async function fetchTasks(params?: {
  status?: string;
  assigned_to?: string;
  limit?: number;
}): Promise<CrmTask[]> {
  const qs = new URLSearchParams();
  if (params?.status) qs.set('status', params.status);
  if (params?.assigned_to) qs.set('assigned_to', params.assigned_to);
  if (params?.limit != null) qs.set('limit', String(params.limit));
  const res = await apiFetch<{ status: string; data: CrmTask[] }>(`/api/crm/tasks?${qs}`);
  return res.data;
}

export async function createTask(body: {
  person_id: string;
  lead_id?: string;
  reminder_type?: string;
  title: string;
  notes?: string;
  due_at?: string;
  priority?: string;
}): Promise<{ reminder_id: string; title: string }> {
  const res = await apiFetch<{ status: string; data: { reminder_id: string; title: string } }>('/api/crm/tasks', {
    method: 'POST',
    body: JSON.stringify(body),
  });
  return res.data;
}

export async function updateTask(body: {
  reminder_id: string;
  status: 'pending' | 'done' | 'snoozed' | 'cancelled';
  due_at?: string;
  notes?: string;
}): Promise<CrmTask> {
  const res = await apiFetch<{ status: string; data: CrmTask }>(`/api/crm/tasks/${body.reminder_id}`, {
    method: 'PATCH',
    body: JSON.stringify({
      status: body.status,
      due_at: body.due_at,
      notes: body.notes,
    }),
  });
  return res.data;
}

// ── Kanban ────────────────────────────────────────────────────────────────────

export async function fetchKanbanBoard(): Promise<KanbanColumn[]> {
  const res = await apiFetch<{ status: string; data: KanbanColumn[] }>('/api/crm/kanban');
  return res.data;
}

export async function updateLeadStage(body: {
  lead_id: string;
  status: string;
  notes?: string;
}): Promise<CrmLeadStageUpdate> {
  const res = await apiFetch<{ status: string; data: CrmLeadStageUpdate }>(`/api/crm/leads/${body.lead_id}/stage`, {
    method: 'PATCH',
    body: JSON.stringify({
      status: body.status,
      notes: body.notes,
    }),
  });
  return res.data;
}

// ── QD Scores ─────────────────────────────────────────────────────────────────

export async function fetchQdScore(personId: string): Promise<{
  person_id: string;
  scores: Record<string, QdScoreEntry>;
  timeseries: Array<{ score_type: string; value: number; timestamp: string | null; signal_source: string | null; delta: number | null }>;
}> {
  const res = await apiFetch<{
    status: string;
    data: {
      person_id: string;
      scores: Record<string, QdScoreEntry>;
      timeseries: Array<{ score_type: string; value: number; timestamp: string | null; signal_source: string | null; delta: number | null }>;
    };
  }>(`/api/crm/qd/${personId}`);
  return res.data;
}

// ── Import Batches ─────────────────────────────────────────────────────────────

export async function uploadCrmImport(file: File, sourceSystem = 'csv_upload'): Promise<{
  batch_id: string;
  row_count: number;
  mapped_columns: number;
  unmapped_columns: number;
  mapping_confidence: number;
  proposals_created: number;
  parse_errors: string[];
  lifecycle: string;
  message: string;
}> {
  const form = new FormData();
  form.append('file', file);
  const res = await fetch(`${API_BASE}/api/crm/imports?source_system=${sourceSystem}`, {
    method: 'POST',
    headers: { ...getAuthHeaders() },
    body: form,
  });
  if (!res.ok) {
    const err = await res.json().catch(() => ({ detail: res.statusText }));
    throw new Error(err.detail ?? `Upload error ${res.status}`);
  }
  const json = await res.json();
  return json.data;
}

export async function fetchImportBatches(lifecycle?: string): Promise<ImportBatchSummary[]> {
  const qs = lifecycle ? `?lifecycle=${lifecycle}` : '';
  const res = await apiFetch<{ status: string; data: ImportBatchSummary[] }>(`/api/crm/imports${qs}`);
  return res.data;
}

export async function fetchImportBatch(batchId: string): Promise<{
  batch_id: string;
  filename: string;
  row_count: number;
  mapping_manifest: Record<string, unknown>;
  lifecycle: string;
  proposals: ImportProposal[];
  proposal_count: number;
}> {
  const res = await apiFetch<{ status: string; data: ReturnType<typeof fetchImportBatch> extends Promise<infer R> ? R : never }>(`/api/crm/imports/${batchId}`);
  return res.data as Awaited<ReturnType<typeof fetchImportBatch>>;
}

export async function reviewProposal(
  batchId: string,
  proposalId: string,
  decision: ImportReviewDecision,
  notes = ''
): Promise<{ decision_id: string; decision: string }> {
  const res = await apiFetch<{ status: string; data: { decision_id: string; decision: string } }>(
    `/api/crm/imports/${batchId}/review-proposal`,
    {
      method: 'PUT',
      body: JSON.stringify({ proposal_id: proposalId, decision, notes }),
    }
  );
  return res.data;
}

export async function commitImportBatch(batchId: string): Promise<{
  committed: number;
  skipped: number;
  errors: string[];
  lifecycle: string;
}> {
  const res = await apiFetch<{
    status: string;
    data: { committed: number; skipped: number; errors: string[]; lifecycle: string };
  }>(`/api/crm/imports/${batchId}/commit`, { method: 'POST' });
  return res.data;
}

export async function fetchOracleClientData(params?: {
  search?: string;
  limit?: number;
  offset?: number;
}): Promise<{ items: OracleClientDataListItem[]; count: number }> {
  const qs = new URLSearchParams();
  if (params?.search) qs.set('search', params.search);
  if (params?.limit != null) qs.set('limit', String(params.limit));
  if (params?.offset != null) qs.set('offset', String(params.offset));
  const res = await apiFetch<{ status: string; data: OracleClientDataListItem[]; meta?: { count?: number } }>(
    `/api/crm/client-data?${qs}`,
  );
  return { items: res.data, count: res.meta?.count ?? res.data.length };
}

export async function fetchOracleClientDataDetail(personId: string): Promise<OracleClientDataDetail> {
  const res = await apiFetch<{ status: string; data: OracleClientDataDetail }>(`/api/crm/client-data/${personId}`);
  return res.data;
}

export async function patchOracleClientData(
  personId: string,
  patch: Record<string, string | null>,
): Promise<{ person_id: string; updated: string[] }> {
  const res = await apiFetch<{ status: string; data: { person_id: string; updated: string[] } }>(
    `/api/crm/client-data/${personId}`,
    { method: 'PATCH', body: JSON.stringify(patch) },
  );
  return res.data;
}

export async function fetchOracleClientTimeline(personId: string): Promise<OracleClientTimelineItem[]> {
  const res = await apiFetch<{ status: string; data: OracleClientTimelineItem[] }>(
    `/api/crm/client-data/${personId}/timeline`,
  );
  return res.data;
}
