// ===== lib-api.jsx =====
// 极简 API 客户端，挂在 window.API。所有方法返回 Promise。
// 失败时 reject 一个 ApiError，含 status / code / message / detail。

class ApiError extends Error {
  constructor({ status, code, message, detail }) {
    super(message || 'API 请求失败');
    this.status = status;
    this.code = code || 'unknown';
    this.detail = detail || {};
  }
}

const BASE = ''; // 同源，走 Caddy 反代

async function _req(method, path, { body, headers, formData } = {}) {
  const opts = { method, headers: { ...(headers || {}) } };
  if (formData) {
    opts.body = formData;
  } else if (body !== undefined) {
    opts.body = JSON.stringify(body);
    opts.headers['Content-Type'] = 'application/json';
  }
  const resp = await fetch(BASE + path, opts);

  let payload = null;
  const text = await resp.text();
  try { payload = text ? JSON.parse(text) : null; } catch (_) { payload = { raw: text }; }

  if (!resp.ok) {
    throw new ApiError({
      status: resp.status,
      code: (payload && payload.code) || `http_${resp.status}`,
      message: (payload && payload.message) || `请求失败 (${resp.status})`,
      detail: (payload && payload.detail) || payload,
    });
  }
  return payload;
}

const TOKEN_PREFIX = 'mojian:token:';

window.API = {
  ApiError,

  // ----- 凭证管理（localStorage：跨 tab 跨刷新跨重启都保留） -----
  saveToken(orderId, token) {
    if (!orderId || !token) return;
    try {
      localStorage.setItem(TOKEN_PREFIX + orderId, token);
    } catch (e) {
      // 隐私模式下 localStorage 可能不可写，降级用 sessionStorage
      try { sessionStorage.setItem(TOKEN_PREFIX + orderId, token); } catch (_) {}
    }
  },
  getToken(orderId) {
    return (
      localStorage.getItem(TOKEN_PREFIX + orderId) ||
      sessionStorage.getItem(TOKEN_PREFIX + orderId) ||
      ''
    );
  },
  clearToken(orderId) {
    try { localStorage.removeItem(TOKEN_PREFIX + orderId); } catch (_) {}
    try { sessionStorage.removeItem(TOKEN_PREFIX + orderId); } catch (_) {}
  },

  // ----- 公开 API -----
  async uploadOrder(file) {
    const fd = new FormData();
    fd.append('file', file);
    return _req('POST', '/api/orders', { formData: fd });
  },

  async getOrder(orderId) {
    return _req('GET', `/api/orders/${encodeURIComponent(orderId)}`);
  },

  async getReport(orderId, token) {
    const t = token || this.getToken(orderId);
    return _req('GET', `/api/orders/${encodeURIComponent(orderId)}/report?token=${encodeURIComponent(t)}`);
  },

  getReportPdfUrl(orderId, token) {
    const t = token || this.getToken(orderId);
    return `/api/orders/${encodeURIComponent(orderId)}/report/pdf?token=${encodeURIComponent(t)}`;
  },

  async trial(text) {
    const fd = new FormData();
    fd.append('text', text);
    return _req('POST', '/api/orders/trial', { formData: fd });
  },

  async joinWaitlist(payload) {
    return _req('POST', '/api/waitlist', { body: payload });
  },

  // ----- 管理员 API（Basic Auth） -----
  ADMIN_KEY: 'mojian:admin:basic',
  saveAdmin(username, password) {
    sessionStorage.setItem(this.ADMIN_KEY, btoa(`${username}:${password}`));
  },
  clearAdmin() {
    sessionStorage.removeItem(this.ADMIN_KEY);
  },
  isAdminLoggedIn() {
    return !!sessionStorage.getItem(this.ADMIN_KEY);
  },
  _adminHeaders() {
    const b64 = sessionStorage.getItem(this.ADMIN_KEY);
    if (!b64) throw new ApiError({ status: 401, code: 'not_logged_in', message: '未登录' });
    return { Authorization: 'Basic ' + b64 };
  },

  async adminListOrders({ status, amount_suffix, q, limit = 50, offset = 0 } = {}) {
    const params = new URLSearchParams();
    if (status) params.set('status', status);
    if (amount_suffix !== undefined && amount_suffix !== null && amount_suffix !== '') {
      params.set('amount_suffix', String(amount_suffix));
    }
    if (q) params.set('q', q);
    params.set('limit', String(limit));
    params.set('offset', String(offset));
    return _req('GET', '/api/admin/orders?' + params.toString(), { headers: this._adminHeaders() });
  },

  async adminConfirm(orderId, note = '') {
    return _req('POST', `/api/admin/orders/${encodeURIComponent(orderId)}/confirm`,
      { body: { note }, headers: this._adminHeaders() });
  },

  async adminRefund(orderId, reason = '') {
    return _req('POST', `/api/admin/orders/${encodeURIComponent(orderId)}/refund`,
      { body: { reason }, headers: this._adminHeaders() });
  },

  async adminReprocess(orderId) {
    return _req('POST', `/api/admin/orders/${encodeURIComponent(orderId)}/reprocess`,
      { body: {}, headers: this._adminHeaders() });
  },

  async adminStats() {
    return _req('GET', '/api/admin/stats', { headers: this._adminHeaders() });
  },

  async adminWaitlist({ tier, limit = 100 } = {}) {
    const params = new URLSearchParams();
    if (tier) params.set('tier', tier);
    params.set('limit', String(limit));
    return _req('GET', '/api/admin/waitlist?' + params.toString(), { headers: this._adminHeaders() });
  },
};
