// frontend/api.jsx — backend client + demo-shape adapter.
// Served from / by FastAPI StaticFiles, so same origin — no CORS.

const API_BASE = "/api";

async function authHeaders() {
  const getToken = window.getAuthToken;
  if (!getToken) return {};
  const token = await getToken();
  return token ? { Authorization: `Bearer ${token}` } : {};
}

async function createJob(blob, filename, formKind) {
  const fd = new FormData();
  fd.append("form_kind", formKind);
  fd.append("audio", blob, filename);
  const resp = await fetch(`${API_BASE}/jobs`, {
    method: "POST",
    body: fd,
    headers: await authHeaders(),
  });
  if (!resp.ok) {
    const detail = await resp.text();
    throw new Error(`POST /api/jobs ${resp.status}: ${detail}`);
  }
  return resp.json();
}

async function createImageJob(file, formKind) {
  const fd = new FormData();
  fd.append("form_kind", formKind);
  fd.append("image", file, file.name);
  const resp = await fetch(`${API_BASE}/jobs`, {
    method: "POST",
    body: fd,
    headers: await authHeaders(),
  });
  if (!resp.ok) {
    const detail = await resp.text();
    throw new Error(`POST /api/jobs ${resp.status}: ${detail}`);
  }
  return resp.json();
}

async function getJob(jobId) {
  const resp = await fetch(`${API_BASE}/jobs/${jobId}`, {
    headers: await authHeaders(),
  });
  if (resp.status === 404) throw new Error("job not found");
  if (!resp.ok) throw new Error(`GET /api/jobs ${resp.status}`);
  return resp.json();
}

// Poll every intervalMs until status is done or failed, calling onState(state)
// on every tick. Abortable via AbortSignal.
async function pollJob(jobId, { intervalMs = 2000, signal, onState } = {}) {
  while (true) {
    if (signal && signal.aborted) throw new Error("polling aborted");
    const state = await getJob(jobId);
    if (onState) onState(state);
    if (state.status === "done" || state.status === "failed") return state;
    await new Promise(r => setTimeout(r, intervalMs));
  }
}

// Adapt flat backend payload into the frontend's {value, c, note} shape.
function adaptBackend(state) {
  const fields = state.extracted_fields || {};
  const conf = state.field_confidence || {};
  const notes = state.field_notes || {};
  const rejected = state.rejected_values || {};
  const lowConf = new Set(state.low_confidence_fields || []);
  const out = {};
  for (const [key, value] of Object.entries(fields)) {
    if (key === "itr_filing_status") continue; // pulled out separately
    let c = conf[key];
    if (c === undefined) c = value == null ? null : 0.95;
    let note = notes[key] || null;
    if (!note && rejected[key] != null) note = `Rejected: ${rejected[key]}`;
    const status = lowConf.has(key) ? "low" : undefined;
    out[key] = { value, c, note, status };
  }
  return {
    transcript: state.transcript,
    durationSec: state.duration_sec,
    fields: out,
    missingRequired: state.missing_required_fields || [],
    itr: fields.itr_filing_status || null,
  };
}

Object.assign(window, { createJob, createImageJob, getJob, pollJob, adaptBackend });
