const TOKEN_KEY = "gost_api_token";

export function getToken() {
  return localStorage.getItem(TOKEN_KEY) || "";
}

export function setToken(token) {
  localStorage.setItem(TOKEN_KEY, token || "");
}

function parseErrorBody(xhr) {
  let detail = xhr.statusText || "Request failed";
  try {
    const data = JSON.parse(xhr.responseText);
    detail = data.detail || JSON.stringify(data);
  } catch (_) {
    /* ignore */
  }
  return typeof detail === "string" ? detail : JSON.stringify(detail);
}

async function request(path, options = {}) {
  const headers = new Headers(options.headers || {});
  const token = getToken();
  if (token) headers.set("Authorization", `Bearer ${token}`);
  if (options.json !== undefined) {
    headers.set("Content-Type", "application/json");
  }
  const res = await fetch(path, {
    ...options,
    headers,
    body: options.json !== undefined ? JSON.stringify(options.json) : options.body,
  });
  if (!res.ok) {
    let detail = res.statusText;
    try {
      const data = await res.json();
      detail = data.detail || JSON.stringify(data);
    } catch (_) {
      /* ignore */
    }
    throw new Error(typeof detail === "string" ? detail : JSON.stringify(detail));
  }
  if (res.status === 204) return null;
  const ct = res.headers.get("content-type") || "";
  if (ct.includes("application/json")) return res.json();
  return res.blob();
}

export const api = {
  listProjects: () => request("/api/projects"),
  createProject: (name) => request("/api/projects", { method: "POST", json: { name } }),
  getProject: (id) => request(`/api/projects/${id}`),
  updateProject: (id, data) => request(`/api/projects/${id}`, { method: "PATCH", json: data }),
  deleteProject: (id) => request(`/api/projects/${id}`, { method: "DELETE" }),
  uploadZip: (id, file, method = "POST", keepTables = true, onProgress) => {
    const fd = new FormData();
    fd.append("file", file);
    const q = method === "PUT" ? `?keep_tables=${keepTables}` : "";

    return new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest();
      xhr.open(method, `/api/projects/${id}/upload${q}`);
      const token = getToken();
      if (token) xhr.setRequestHeader("Authorization", `Bearer ${token}`);

      const report = (phase, loaded, total) => {
        if (!onProgress) return;
        const safeTotal = total || file.size || loaded;
        const percent =
          safeTotal > 0 ? Math.min(100, Math.round((loaded / safeTotal) * 100)) : 0;
        onProgress({
          phase,
          loaded,
          total: safeTotal,
          percent,
          fileName: file.name,
          fileSize: file.size,
        });
      };

      xhr.upload.onprogress = (e) => {
        report("upload", e.loaded, e.lengthComputable ? e.total : file.size);
      };

      xhr.upload.onload = () => {
        report("processing", file.size, file.size);
      };

      xhr.onload = () => {
        if (xhr.status >= 200 && xhr.status < 300) {
          try {
            resolve(JSON.parse(xhr.responseText));
          } catch {
            reject(new Error("Некорректный ответ сервера"));
          }
          return;
        }
        reject(new Error(parseErrorBody(xhr)));
      };

      xhr.onerror = () => reject(new Error("Ошибка сети при загрузке файла"));
      xhr.onabort = () => reject(new Error("Загрузка отменена"));
      xhr.ontimeout = () => reject(new Error("Превышено время ожидания загрузки"));

      report("upload", 0, file.size);
      xhr.send(fd);
    });
  },
  getComponents: (id) => request(`/api/projects/${id}/components`),
  getParams: (id) => request(`/api/projects/${id}/params`),
  getPcb: (id) => request(`/api/projects/${id}/pcb`),
  getInscriptions: (id) => request(`/api/projects/${id}/inscriptions`),
  patchInscriptions: (id, inscriptions) =>
    request(`/api/projects/${id}/inscriptions`, { method: "PATCH", json: { inscriptions } }),
  getTable: (id, type) => request(`/api/projects/${id}/tables/${type}`),
  patchTable: (id, type, rows) =>
    request(`/api/projects/${id}/tables/${type}`, { method: "PATCH", json: { rows } }),
  generateTable: (id, type, body = {}) =>
    request(`/api/projects/${id}/tables/${type}/generate`, { method: "POST", json: body }),
  exportDoc: async (id, table_type, format) => {
    const blob = await request(`/api/projects/${id}/export`, {
      method: "POST",
      json: { table_type, format },
    });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = `project_${id}_${table_type}.${format}`;
    a.click();
    URL.revokeObjectURL(url);
  },
  llmChat: (id, message, table_type) =>
    request(`/api/projects/${id}/llm/chat`, { method: "POST", json: { message, table_type } }),
  llmApply: (id, table_type, edits) =>
    request(`/api/projects/${id}/llm/apply`, { method: "POST", json: { table_type, edits } }),
};
