// API client — reads credentials from localStorage, injects headers on every request.
// All functions return parsed JSON or throw an Error with .message set.

const API_BASE = "";   // same origin (served by FastAPI)

const LS = {
  token:       "jwt_token",
  rpaHost:     "rpa_host",
  rpaPort:     "rpa_port",
  rpaGitUrl:   "rpa_git_url",
  rpaPrompt:   "rpa_prompt",          // 自定义分析提示词（空 = 使用服务端默认）
  feishuFields:"feishu_fields_json",  // Hermes 推导的字段定义（JSON 字符串，仅供展示）
  hermesKey:   "hermes_api_key",
  hermesUrl:   "hermes_api_url",
  feishuId:    "feishu_app_id",
  feishuSecret:"feishu_app_secret",
  feishuBase:  "feishu_base_token",
  feishuMeta:  "feishu_metadata_table_id",
  feishuAna:   "feishu_analysis_table_id",
  feishuFolder:"feishu_doc_folder",
  userId:      "user_id",
  userEmail:   "user_email",
  commentLimit: "comment_limit",      // 评论抓取条数（字符串，默认 "100"）
  commentAll:   "comment_fetch_all",  // "1" = 全量，空 = 按 commentLimit
};

window.LS = LS;

// ── 前端日志环形缓冲（供反馈功能采集）──────────────────────────────────────
// 固定长度，超出丢弃最早的。绝不采集 localStorage 里的 Key。
const _LOG_CAP = 200;
const _logBuffer = [];

// 脱敏：擦掉疑似密钥/令牌的内容，避免反馈时泄露
const _SECRET_RE = [
  /(?:authorization|bearer)\s*[:=]?\s*\S+/gi,
  /(?:api[_-]?key|secret|token|password|app[_-]?secret)\s*[:=]\s*\S+/gi,
  /\bAIza[0-9A-Za-z\-_]{20,}\b/g,                                  // Google API key
  /\beyJ[0-9A-Za-z\-_]+\.[0-9A-Za-z\-_]+\.[0-9A-Za-z\-_]+/g,       // JWT
];
function _scrub(s) {
  let t = String(s);
  for (const re of _SECRET_RE) t = t.replace(re, "[REDACTED]");
  return t;
}

function _pushLog(level, msg) {
  _logBuffer.push({ ts: new Date().toISOString(), level, msg: _scrub(msg).slice(0, 1000) });
  if (_logBuffer.length > _LOG_CAP) _logBuffer.shift();
}

// monkey-patch console，保留原行为同时写入缓冲
(function patchConsole() {
  ["log", "info", "warn", "error"].forEach(level => {
    const orig = console[level] ? console[level].bind(console) : function(){};
    console[level] = function (...args) {
      try {
        const msg = args.map(a => {
          if (typeof a === "string") return a;
          try { return JSON.stringify(a); } catch { return String(a); }
        }).join(" ");
        _pushLog(level, msg);
      } catch {}
      orig(...args);
    };
  });
  // 捕获未处理异常
  window.addEventListener("error", e => _pushLog("error", `uncaught: ${e.message} @ ${e.filename}:${e.lineno}`));
  window.addEventListener("unhandledrejection", e => _pushLog("error", `unhandledrejection: ${e.reason}`));
})();

window.__getLogBuffer = () => _logBuffer.slice();

function _get(key) { return localStorage.getItem(key) || ""; }

function _authHeaders() {
  const token = _get(LS.token);
  if (!token) throw new Error("未登录，请先登录");
  return { "Authorization": `Bearer ${token}` };
}

function _keyHeaders() {
  const feishuId     = _get(LS.feishuId);
  const feishuSecret = _get(LS.feishuSecret);
  const feishuBase   = _get(LS.feishuBase);
  const feishuMeta   = _get(LS.feishuMeta);
  const feishuAna    = _get(LS.feishuAna);
  const rpaHost      = _get(LS.rpaHost);
  const rpaPort      = _get(LS.rpaPort);
  const rpaGitUrl    = _get(LS.rpaGitUrl);

  const missingFeishu = !feishuId || !feishuSecret || !feishuBase || !feishuMeta || !feishuAna;
  const missingRpa    = !rpaHost || !rpaPort || !rpaGitUrl;

  if (missingFeishu) throw new Error("请先在设置页填写飞书配置（App ID / Secret / Base Token / 两张表 ID）");
  if (missingRpa)    throw new Error("请先在设置页填写 RPA 服务地址、端口和 Git 仓库地址");

  const rpaUrl = `http://${rpaHost}:${rpaPort}`;
  const h = {
    "X-Feishu-App-Id":            feishuId,
    "X-Feishu-App-Secret":        feishuSecret,
    "X-Feishu-Base-Token":        feishuBase,
    "X-Feishu-Metadata-Table-Id": feishuMeta,
    "X-Feishu-Analysis-Table-Id": feishuAna,
    "X-Rpa-Url":                  rpaUrl,
    "X-Rpa-Git-Url":              rpaGitUrl,
  };
  const folder = _get(LS.feishuFolder);
  if (folder) h["X-Feishu-Doc-Folder"] = folder;
  // 自定义提示词：有内容才传，空时服务端使用默认 prompt 文件
  const rpaPrompt = _get(LS.rpaPrompt);
  if (rpaPrompt) h["X-Rpa-Prompt"] = rpaPrompt;
  const hermesUrl = _get(LS.hermesUrl);
  const hermesKey = _get(LS.hermesKey);
  if (hermesUrl) h["X-Hermes-Url"] = hermesUrl;
  if (hermesKey) h["X-Hermes-Key"] = hermesKey;
  // 评论抓取配置（始终传，后端有默认值兜底）
  h["X-Comment-Limit"] = _get(LS.commentLimit) || "100";
  if (_get(LS.commentAll) === "1") h["X-Comment-Fetch-All"] = "1";
  return h;
}

function _hermesHeaders() {
  /** 仅需 Hermes 凭证（用于提示词优化/字段推导，不需要飞书/RPA 配置）。 */
  const hermesUrl = _get(LS.hermesUrl);
  const hermesKey = _get(LS.hermesKey);
  if (!hermesUrl || !hermesKey) throw new Error("请先在设置页填写 Hermes API URL 和 Key");
  return { "X-Hermes-Url": hermesUrl, "X-Hermes-Key": hermesKey };
}

async function _fetch(path, opts = {}) {
  const _t0 = performance.now();
  const _method = (opts.method || "GET").toUpperCase();
  let resp;
  try {
    resp = await fetch(API_BASE + path, {
      ...opts,
      headers: { "Content-Type": "application/json", ...(opts.headers || {}) },
    });
  } catch (netErr) {
    _pushLog("net", `${_method} ${path} → 网络错误: ${netErr.message}`);
    throw netErr;
  }
  _pushLog("net", `${_method} ${path} → ${resp.status} (${Math.round(performance.now() - _t0)}ms)`);
  const text = await resp.text();
  let data;
  try { data = JSON.parse(text); } catch { data = { detail: text }; }
  if (!resp.ok) {
    // JWT 过期 / 无效 → 清除 token，1.5s 后刷新到登录页
    // 注意：只有携带了 Authorization 头的请求（即已登录状态）返回 401 时才视为 token 过期。
    // 登录/注册请求本身不带 Authorization，若密码错误后端也返回 401，
    // 不应触发此逻辑，应让下面的正常错误处理显示真实原因。
    if (resp.status === 401 && opts.headers && ("Authorization" in opts.headers)) {
      localStorage.removeItem(LS.token);
      setTimeout(() => window.location.reload(), 1500);
      throw new Error("登录已过期，请重新登录（1.5 秒后自动跳转到登录页）");
    }
    let detail = data.detail;
    if (Array.isArray(detail)) {
      detail = detail.map(e => e.msg || JSON.stringify(e)).join("; ");
    } else if (detail && typeof detail !== "string") {
      detail = JSON.stringify(detail);
    }
    throw new Error(detail || `HTTP ${resp.status}`);
  }
  return data;
}

// ── Auth ─────────────────────────────────────────────────────────────────────

window.API = {
  async register(email, password) {
    const data = await _fetch("/auth/register", {
      method: "POST",
      body: JSON.stringify({ email, password }),
    });
    localStorage.setItem(LS.token, data.token);
    localStorage.setItem(LS.userId, data.user_id);
    localStorage.setItem(LS.userEmail, email);
    return data;
  },

  async login(email, password) {
    const data = await _fetch("/auth/login", {
      method: "POST",
      body: JSON.stringify({ email, password }),
    });
    localStorage.setItem(LS.token, data.token);
    localStorage.setItem(LS.userId, data.user_id);
    localStorage.setItem(LS.userEmail, email);
    return data;
  },

  logout() {
    [LS.token, LS.userId, LS.userEmail].forEach(k => localStorage.removeItem(k));
  },

  isLoggedIn() {
    return !!localStorage.getItem(LS.token);
  },

  currentEmail() {
    return localStorage.getItem(LS.userEmail) || "";
  },

  // ── Jobs ────────────────────────────────────────────────────────────────────

  async submitCollect(url) {
    return _fetch("/api/jobs/collect", {
      method: "POST",
      headers: { ..._authHeaders(), ..._keyHeaders() },
      body: JSON.stringify({ url }),
    });
  },

  /**
   * 关键词搜索预览：只需 JWT，返回视频列表，不创建 Job。
   * platform: "youtube" | "bilibili"
   */
  async searchPreview(keyword, platform = "youtube", maxResults = 20) {
    return _fetch("/api/collect/preview", {
      method: "POST",
      headers: _authHeaders(),
      body: JSON.stringify({ keyword, platform, max_results: maxResults }),
    });
  },

  /**
   * 批量采集：为 urls 数组中每个 URL 创建独立 Job。
   * 需要 JWT + API Keys（飞书 + RPA）。
   */
  async batchCollect(urls) {
    return _fetch("/api/collect/batch", {
      method: "POST",
      headers: { ..._authHeaders(), ..._keyHeaders() },
      body: JSON.stringify({ urls }),
    });
  },

  async getJob(jobId) {
    return _fetch(`/api/jobs/${jobId}`, {
      headers: _authHeaders(),
    });
  },

  async listJobs() {
    return _fetch("/api/jobs", {
      headers: _authHeaders(),
    });
  },

  // ── Videos ──────────────────────────────────────────────────────────────────

  async listVideos(filters = {}) {
    const params = new URLSearchParams();
    Object.entries(filters).forEach(([k, v]) => { if (v !== undefined && v !== null && v !== "") params.set(k, v); });
    const qs = params.toString();
    return _fetch(`/api/videos${qs ? "?" + qs : ""}`, {
      headers: _authHeaders(),
    });
  },

  async getVideo(videoId) {
    return _fetch(`/api/videos/${videoId}`, {
      headers: _authHeaders(),
    });
  },

  // ── Search ──────────────────────────────────────────────────────────────────

  async search(query, topK = 20) {
    return _fetch("/api/search", {
      method: "POST",
      headers: { ..._authHeaders(), ..._keyHeaders() },
      body: JSON.stringify({ query, top_k: topK }),
    });
  },

  // ── Hermes ──────────────────────────────────────────────────────────────────

  async checkHermesWiki() {
    // 只需 JWT + Hermes URL/Key，不需要飞书/RPA 配置
    return _fetch("/api/hermes/check-wiki", {
      method: "POST",
      headers: { ..._authHeaders(), ..._hermesHeaders() },
    });
  },

  async initHermesWiki(agentsMd) {
    // 只需 JWT + Hermes URL/Key
    return _fetch("/api/hermes/init-wiki", {
      method: "POST",
      headers: { ..._authHeaders(), ..._hermesHeaders() },
      body: JSON.stringify({ agents_md: agentsMd }),
    });
  },

  // ── Test ────────────────────────────────────────────────────────────────────

  /**
   * Verify Feishu credentials and permissions step by step.
   * Reads keys from localStorage (save first if you changed them on-screen).
   * Returns { auth, base_read, base_write, doc_folder } — each { ok, msg }.
   */
  async testFeishu() {
    const feishuId     = _get(LS.feishuId);
    const feishuSecret = _get(LS.feishuSecret);
    const feishuBase   = _get(LS.feishuBase);
    const feishuMeta   = _get(LS.feishuMeta);
    const feishuAna    = _get(LS.feishuAna);
    if (!feishuId || !feishuSecret || !feishuBase || !feishuMeta || !feishuAna)
      throw new Error("请先填写完整的飞书配置（App ID / Secret / Base Token / 两张表 ID）");
    const headers = {
      ..._authHeaders(),
      "X-Feishu-App-Id":             feishuId,
      "X-Feishu-App-Secret":         feishuSecret,
      "X-Feishu-Base-Token":         feishuBase,
      "X-Feishu-Metadata-Table-Id":  feishuMeta,
      "X-Feishu-Analysis-Table-Id":  feishuAna,
    };
    const folder = _get(LS.feishuFolder);
    if (folder) headers["X-Feishu-Doc-Folder"] = folder;
    return _fetch("/api/test/feishu", { method: "POST", headers });
  },

  // ── Prompt ──────────────────────────────────────────────────────────────────

  /** 获取服务端默认提示词（首次加载时填充 textarea）。 */
  async getDefaultPrompt() {
    return _fetch("/api/prompt/default", { headers: _authHeaders() });
  },

  /**
   * 使用 Hermes 优化提示词。
   * 不需要飞书/RPA 配置，只需 Hermes URL + Key。
   */
  async optimizePrompt(prompt) {
    return _fetch("/api/prompt/optimize", {
      method: "POST",
      headers: { ..._authHeaders(), ..._hermesHeaders() },
      body: JSON.stringify({ prompt }),
    });
  },

  /**
   * 使用 Hermes 推导飞书字段定义。
   * 返回 { fields: [{name, type, label, description}] }
   */
  async genFeishuFields(prompt) {
    return _fetch("/api/prompt/gen-fields", {
      method: "POST",
      headers: { ..._authHeaders(), ..._hermesHeaders() },
      body: JSON.stringify({ prompt }),
    });
  },

  // ── RPA ─────────────────────────────────────────────────────────────────────

  /**
   * 检测 RPA 服务是否可达。
   * 后端会代理请求到 {rpa_url}/ping，避免跨域问题。
   * 返回 { reachable: bool, status?, error? }
   */
  async pingRpa() {
    const rpaHost = _get(LS.rpaHost);
    const rpaPort = _get(LS.rpaPort);
    if (!rpaHost || !rpaPort) throw new Error("未配置 RPA 服务地址");
    const rpaUrl = `http://${rpaHost}:${rpaPort}`;
    return _fetch("/api/rpa/ping", {
      headers: {
        ..._authHeaders(),
        "X-Rpa-Url": rpaUrl,
      },
    });
  },

  // ── Health ──────────────────────────────────────────────────────────────────

  async health() {
    return _fetch("/health");
  },

  // ── Feedback ──────────────────────────────────────────────────────────────────

  /**
   * 提交反馈 → 后端聚合前后端日志生成 GitHub Issue。
   * 支持匿名（登录页也能反馈）：已登录则带 JWT，否则后端记为 anonymous。
   * 自动附带脱敏后的前端日志缓冲、当前页面、UA。
   * 返回 { issue_number, issue_url, message }
   */
  async submitFeedback(description) {
    const token = _get(LS.token);
    const headers = token ? { "Authorization": `Bearer ${token}` } : {};
    return _fetch("/api/feedback", {
      method: "POST",
      headers,
      body: JSON.stringify({
        description,
        page: token ? (localStorage.getItem("__page") || "") : "login",
        user_agent: navigator.userAgent,
        client_logs: (window.__getLogBuffer ? window.__getLogBuffer() : []),
        ts: new Date().toISOString(),
      }),
    });
  },
};
