// ── API client ────────────────────────────────────────────────────────────────

const API_BASE = '/api';

function getLang()        { return localStorage.getItem('lang') || 'en'; }
function setLang(lang)    { localStorage.setItem('lang', lang); }

function getAccess()  { return localStorage.getItem('access'); }
function getRefresh() { return localStorage.getItem('refresh'); }

function setTokens(access, refresh) {
  localStorage.setItem('access', access);
  if (refresh) localStorage.setItem('refresh', refresh);
}

function clearTokens() {
  localStorage.removeItem('access');
  localStorage.removeItem('refresh');
}

async function refreshAccess() {
  const refresh = getRefresh();
  if (!refresh) throw new Error('no refresh token');
  const res = await fetch(`${API_BASE}/auth/token/refresh/`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ refresh }),
  });
  if (!res.ok) throw new Error('refresh failed');
  const data = await res.json();
  setTokens(data.access, data.refresh || refresh);
  return data.access;
}

async function apiFetch(path, opts = {}) {
  const headers = { ...opts.headers };
  if (!(opts.body instanceof FormData)) {
    headers['Content-Type'] = headers['Content-Type'] || 'application/json';
  }
  headers['Accept-Language'] = getLang();
  const access = getAccess();
  if (access) headers['Authorization'] = `Bearer ${access}`;

  let res = await fetch(`${API_BASE}${path}`, { ...opts, headers });

  if (res.status === 401) {
    try {
      const newAccess = await refreshAccess();
      headers['Authorization'] = `Bearer ${newAccess}`;
      res = await fetch(`${API_BASE}${path}`, { ...opts, headers });
    } catch {
      clearTokens();
      window.location.href = '/login.html';
      throw new Error('session expired');
    }
  }
  return res;
}

// Convenience helpers ─────────────────────────────────────────────────────────

async function apiGet(path) {
  const res = await apiFetch(path);
  if (!res.ok) throw new Error(`GET ${path} → ${res.status}`);
  return res.json();
}

async function apiPost(path, data) {
  const body = data instanceof FormData ? data : JSON.stringify(data);
  const res = await apiFetch(path, { method: 'POST', body });
  if (!res.ok) {
    const err = await res.json().catch(() => ({}));
    const e = new Error(`POST ${path} → ${res.status}`);
    e.data = err; e.status = res.status;
    throw e;
  }
  return res.status === 204 ? null : res.json();
}

async function apiPatch(path, data) {
  const body = data instanceof FormData ? data : JSON.stringify(data);
  const res = await apiFetch(path, { method: 'PATCH', body });
  if (!res.ok) {
    const err = await res.json().catch(() => ({}));
    const e = new Error(`PATCH ${path} → ${res.status}`);
    e.data = err; e.status = res.status;
    throw e;
  }
  return res.json();
}

async function apiDelete(path) {
  const res = await apiFetch(path, { method: 'DELETE' });
  if (!res.ok) throw new Error(`DELETE ${path} → ${res.status}`);
}

// Fetch ALL pages of a paginated endpoint, returning a flat array.
// path must be relative to API_BASE (e.g. '/calibers/?status=VERIFIED').
async function apiGetAll(path) {
  const results = [];
  let url = path;
  while (url) {
    const res = await apiFetch(url);
    if (!res.ok) throw new Error(`GET ${url} → ${res.status}`);
    const data = await res.json();
    if (Array.isArray(data)) { results.push(...data); break; }
    results.push(...(data.results || []));
    if (data.next) {
      // DRF returns absolute next URLs; strip origin + API_BASE to get a bare path
      try {
        const u = new URL(data.next);
        url = u.pathname.slice(API_BASE.length) + u.search;
      } catch { url = null; }
    } else {
      url = null;
    }
  }
  return results;
}

// Unwrap a DRF response that may be a plain array or a paginated object
function asList(data) {
  return Array.isArray(data) ? data : (data.results || []);
}

// Format API validation errors into a readable string
function formatErrors(errData) {
  if (!errData || typeof errData !== 'object') return 'An error occurred.';
  return Object.entries(errData)
    .map(([k, v]) => `${k}: ${Array.isArray(v) ? v.join(', ') : v}`)
    .join('\n');
}
