// Client API InkFlow : wrappers fetch + abonnement WebSocket a l'etat.

async function j(url, opts) {
  const res = await fetch(url, opts);
  if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
  const ct = res.headers.get("content-type") || "";
  return ct.includes("application/json") ? res.json() : res;
}

const json = (method, body) => ({
  method,
  headers: { "Content-Type": "application/json" },
  body: body ? JSON.stringify(body) : undefined,
});

export const api = {
  listBooks: () => j("/api/books"),
  uploadBook: (file) => {
    const fd = new FormData();
    fd.append("file", file);
    return j("/api/books", { method: "POST", body: fd });
  },
  getBook: (slug) => j(`/api/books/${slug}`),
  getChapter: (slug, idx) => j(`/api/books/${slug}/chapters/${idx}`),
  putAnalysis: (slug, idx, analysis) =>
    j(`/api/books/${slug}/chapters/${idx}/analysis`, json("PUT", analysis)),
  analyze: (slug, chapters) => j(`/api/books/${slug}/analyze`, json("POST", { chapters })),
  pronounce: (slug) => j(`/api/books/${slug}/pronounce`, json("POST")),
  castAuto: (slug) => j(`/api/books/${slug}/cast/auto`, json("POST")),
  castAnalyze: (slug, chapters) =>
    j(`/api/books/${slug}/cast/analyze`, json("POST", { chapters })),
  castDedup: (slug) => j(`/api/books/${slug}/cast/dedup`, json("POST")),
  render: (slug, chapters, backend, mono) =>
    j(`/api/books/${slug}/render`, json("POST", { chapters, backend, mono })),
  getCast: (slug) => j(`/api/books/${slug}/cast`),
  putCast: (slug, cast) => j(`/api/books/${slug}/cast`, json("PUT", cast)),
  getPron: (slug) => j(`/api/books/${slug}/pronunciation`),
  putPron: (slug, pron) => j(`/api/books/${slug}/pronunciation`, json("PUT", pron)),
  getSettings: () => j("/api/settings"),
  putSettings: (settings) => j("/api/settings", json("PUT", settings)),
  audioUrl: (slug, idx) => `/api/books/${slug}/audio/${idx}`,
  coverUrl: (slug) => `/api/books/${slug}/cover`,
  previewVoice: async (voiceId, text) => {
    const res = await fetch("/api/voicebank/preview", json("POST", { voice_id: voiceId, text }));
    if (!res.ok) throw new Error("preview");
    return URL.createObjectURL(await res.blob());
  },
};

// Abonnement temps reel a l'etat d'un livre. Reconnecte automatiquement.
export function subscribeState(slug, onState) {
  let ws, closed = false;
  const connect = () => {
    const proto = location.protocol === "https:" ? "wss" : "ws";
    ws = new WebSocket(`${proto}://${location.host}/ws/${slug}`);
    ws.onmessage = (e) => {
      const msg = JSON.parse(e.data);
      if (msg.type === "state") onState(msg.state);
    };
    ws.onclose = () => { if (!closed) setTimeout(connect, 1500); };
  };
  connect();
  return () => { closed = true; ws && ws.close(); };
}
