const state = { csrf: "", page: "overview" };

function $(id) { return document.getElementById(id); }

async function api(path, options = {}) {
  const headers = Object.assign({ "Content-Type": "application/json" }, options.headers || {});
  if (state.csrf && (options.method || "GET") !== "GET") headers["X-CSRF-Token"] = state.csrf;
  const res = await fetch(path, Object.assign({}, options, { headers, credentials: "same-origin" }));
  const body = await res.json();
  if (!res.ok) {
    const msg = (body.error && body.error.message) || body.error || res.statusText;
    throw new Error(msg);
  }
  return body;
}

function show(id) {
  ["login-view", "change-view", "shell"].forEach((key) => { $(key).hidden = key !== id; });
}

function esc(value) {
  return String(value ?? "").replace(/[&<>"]/g, (ch) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" }[ch]));
}

function table(headers, rows) {
  const thead = headers.map((h) => `<th>${esc(h)}</th>`).join("");
  const body = rows.length
    ? rows.map((cols) => `<tr>${cols.map((c) => `<td>${c}</td>`).join("")}</tr>`).join("")
    : `<tr><td colspan="${headers.length}">暂无数据</td></tr>`;
  return `<table><thead><tr>${thead}</tr></thead><tbody>${body}</tbody></table>`;
}

async function boot() {
  try {
    const session = await api("/admin/api/session");
    state.csrf = session.csrf;
    $("who").textContent = session.username;
    if (session.must_change) { show("change-view"); return; }
    show("shell");
    await render();
  } catch {
    show("login-view");
  }
}

$("login-form").addEventListener("submit", async (event) => {
  event.preventDefault();
  const form = new FormData(event.target);
  $("login-error").hidden = true;
  try {
    const result = await api("/admin/api/login", {
      method: "POST",
      body: JSON.stringify({ username: form.get("username"), password: form.get("password") }),
    });
    state.csrf = result.csrf;
    if (result.must_change) show("change-view");
    else { show("shell"); await render(); }
  } catch (err) {
    $("login-error").hidden = false;
    $("login-error").textContent = err.message;
  }
});

$("change-form").addEventListener("submit", async (event) => {
  event.preventDefault();
  const form = new FormData(event.target);
  try {
    await api("/admin/api/change-password", {
      method: "POST",
      body: JSON.stringify({ current: form.get("current"), new_password: form.get("new_password") }),
    });
    show("shell");
    await render();
  } catch (err) {
    $("change-error").hidden = false;
    $("change-error").textContent = err.message;
  }
});

$("logout-btn").addEventListener("click", async () => {
  await api("/admin/api/logout", { method: "POST", body: "{}" });
  show("login-view");
});

$("theme-btn").addEventListener("click", () => {
  const root = document.documentElement;
  const next = root.getAttribute("data-theme") === "night" ? "" : "night";
  if (next) root.setAttribute("data-theme", next);
  else root.removeAttribute("data-theme");
  $("theme-btn").textContent = next ? "日间" : "夜间";
});

document.querySelectorAll("nav button").forEach((btn) => {
  btn.addEventListener("click", () => {
    document.querySelectorAll("nav button").forEach((item) => item.classList.remove("active"));
    btn.classList.add("active");
    state.page = btn.dataset.page;
    render();
  });
});

async function render() {
  const page = $("page");
  if (state.page === "overview") {
    const data = await api("/admin/api/overview");
    $("phase").textContent = data.session_phase;
    const eod = data.eod_status || {};
    const rev = data.revision_status || {};
    const eodLabels = {
      pending_first_attempt: "等待首次尝试",
      waiting_upstream: "等待上游",
      done: "已成功",
      cutoff_failed: "已截止失败",
      closed_day: "休市",
    };
    const revLabels = {
      waiting_review: "等待复核",
      review_failed: "复核失败",
      aligned: "已追平",
      cutoff: "已截止",
      pending_publish: "待发布",
      closed_day: "休市",
    };
    const eodExtra = [];
    if (eod.state === "waiting_upstream") {
      eodExtra.push(`已试 ${eod.attempts} 次`);
      if (eod.next_retry_at) eodExtra.push(`下次重试 ${esc(String(eod.next_retry_at).replace("T", " ").slice(11, 16))}`);
      if (eod.missing_datasets && eod.missing_datasets.length) eodExtra.push(`缺 ${esc(eod.missing_datasets.join(","))}`);
    }
    if (eod.state === "cutoff_failed" && eod.missing_datasets) {
      eodExtra.push(`缺 ${esc(eod.missing_datasets.join(","))}`);
    }
    const revExtra = [];
    if (rev.detail) revExtra.push(esc(String(rev.detail)));
    if (rev.window) revExtra.push(esc(String(rev.window)));
    page.innerHTML = `
      <div class="cards">
        <div class="card"><div class="muted">交易日</div><strong>${esc(data.trade_date)}</strong></div>
        <div class="card"><div class="muted">阶段</div><strong>${esc(data.session_phase)}</strong></div>
        <div class="card"><div class="muted">今日发布</div><strong>${data.publications.length}</strong></div>
        <div class="card"><div class="muted">盘后补跑</div><strong>${esc(eodLabels[eod.state] || eod.state || "-")}</strong><div class="muted">${eodExtra.join(" · ")}</div></div>
        <div class="card"><div class="muted">估值复核</div><strong>${esc(revLabels[rev.state] || rev.state || "-")}</strong><div class="muted">${revExtra.join(" · ")}</div></div>
        <div class="card"><div class="muted">异常批次</div><strong class="${data.anomalies.length ? "fail" : "ok"}">${data.anomalies.length}</strong></div>
      </div>
      <h2>最近调用</h2>
      ${table(["时间", "源", "端点", "结果", "耗时"], data.recent_calls.map((row) => [
        esc(row.created_at), esc(row.provider), esc(row.endpoint),
        row.ok ? '<span class="ok">成功</span>' : `<span class="fail">${esc(row.error)}</span>`,
        `${row.latency_ms ?? "-"} ms`,
      ]))}
    `;
    return;
  }
  if (state.page === "sources") {
    const data = await api("/admin/api/sources");
    page.innerHTML = `<h2>数据源</h2>` + table(
      ["源", "角色", "状态", "凭据", "操作"],
      data.items.map((item) => {
        const cred = item.credential || {};
        const credText = cred.configured ? `已配置 · ${esc(cred.last4 || "****")}` : "未配置";
        return [
          esc(item.provider),
          esc(item.role),
          esc((item.health && (item.health.state || item.health.status)) || "-"),
          credText,
          `<button data-probe="${esc(item.provider)}">探测一次</button>`,
        ];
      }),
    );
    page.querySelectorAll("[data-probe]").forEach((btn) => {
      btn.addEventListener("click", async () => {
        const result = await api(`/admin/api/sources/${btn.dataset.probe}/probe`, { method: "POST", body: "{}" });
        alert(JSON.stringify(result));
        render();
      });
    });
    return;
  }
  if (state.page === "jobs") {
    const data = await api("/admin/api/jobs");
    page.innerHTML = `
      <h2>调度任务</h2>
      ${table(["任务", "时刻", "操作"], data.jobs.map((job) => [
        `${esc(job.id)} · ${esc(job.title)}`, esc(job.at),
        `<button data-run="${esc(job.id)}">手动触发</button>`,
      ]))}
      <h3>最近运行</h3>
      ${table(["ID", "任务", "状态", "开始", "结束", "错误"], data.runs.map((row) => [
        row.id, esc(row.job_id), esc(row.state), esc(row.started_at), esc(row.finished_at), esc(row.error),
      ]))}
    `;
    page.querySelectorAll("[data-run]").forEach((btn) => {
      btn.addEventListener("click", async () => {
        const date = prompt("交易日 YYYYMMDD（可留空=今天）", "") || "";
        await api(`/admin/api/jobs/${btn.dataset.run}/run`, { method: "POST", body: JSON.stringify({ trade_date: date }) });
        render();
      });
    });
    return;
  }
  if (state.page === "release") {
    const date = new Date().toISOString().slice(0, 10).replace(/-/g, "");
    const data = await api(`/admin/api/batches?date=${date}`);
    page.innerHTML = `
      <h2>盘后发布 ${esc(data.trade_date)}</h2>
      <div class="toolbar">
        <label>日期 <input id="rel-date" value="${esc(data.trade_date)}" /></label>
        <button type="button" id="rel-load">查看</button>
        <button type="button" id="rel-backfill">补数</button>
      </div>
      <h3>当前映射</h3>
      ${table(["数据集", "活跃批次", "上一批次", "状态", "发布时间", "操作"], data.publications.map((row) => [
        esc(row.dataset), esc(row.active_batch), esc(row.prev_batch), esc(row.state), esc(row.published_at),
        row.prev_batch ? `<button class="danger" data-rollback="${esc(row.dataset)}">回滚</button>` : "-",
      ]))}
      <h3>批次</h3>
      ${table(["batch_id", "数据集", "状态", "行数", "错误"], data.batches.map((row) => [
        esc(row.batch_id), esc(row.dataset), esc(row.state), row.rows_out ?? "", esc(row.error),
      ]))}
    `;
    $bindRelease(page);
    return;
  }
  if (state.page === "datasets") {
    const data = await api("/admin/api/datasets?date=");
    page.innerHTML = `
      <h2>数据集 / 质量 ${esc(data.trade_date)}</h2>
      ${table(["数据集", "批次", "状态", "发布时间"], data.publications.map((row) => [
        esc(row.dataset), esc(row.active_batch), esc(row.state), esc(row.published_at),
      ]))}
      <h3>源间差异</h3>
      ${table(["指标", "左", "右", "偏差", "样本"], data.diff_reports.map((row) => [
        esc(row.metric), esc(row.left_value), esc(row.right_value), esc(row.deviation), row.sample_count ?? "",
      ]))}
    `;
    return;
  }
  if (state.page === "audit") {
    const data = await api("/admin/api/audit");
    page.innerHTML = `<h2>审计</h2>` + table(
      ["时间", "操作者", "动作", "对象", "详情"],
      data.items.map((row) => [esc(row.created_at), esc(row.actor), esc(row.action), esc(row.target), esc(row.detail)]),
    );
  }
}

function $bindRelease(page) {
  page.querySelector("#rel-load").addEventListener("click", async () => {
    const date = page.querySelector("#rel-date").value;
    const data = await api(`/admin/api/batches?date=${encodeURIComponent(date)}`);
    state.page = "release";
    // re-render with fetched date by writing location hash
    history.replaceState(null, "", `#release-${date}`);
    $("page").innerHTML = renderRelease(data);
    $bindRelease($("page"));
  });
  page.querySelector("#rel-backfill").addEventListener("click", () => dangerous("backfill"));
  page.querySelectorAll("[data-rollback]").forEach((btn) => {
    btn.addEventListener("click", () => dangerous("rollback", btn.dataset.rollback));
  });
}

function renderRelease(data) {
  return `
    <h2>盘后发布 ${esc(data.trade_date)}</h2>
    <div class="toolbar">
      <label>日期 <input id="rel-date" value="${esc(data.trade_date)}" /></label>
      <button type="button" id="rel-load">查看</button>
      <button type="button" id="rel-backfill">补数</button>
    </div>
    <h3>当前映射</h3>
    ${table(["数据集", "活跃批次", "上一批次", "状态", "发布时间", "操作"], data.publications.map((row) => [
      esc(row.dataset), esc(row.active_batch), esc(row.prev_batch), esc(row.state), esc(row.published_at),
      row.prev_batch ? `<button class="danger" data-rollback="${esc(row.dataset)}">回滚</button>` : "-",
    ]))}
    <h3>批次</h3>
    ${table(["batch_id", "数据集", "状态", "行数", "错误"], data.batches.map((row) => [
      esc(row.batch_id), esc(row.dataset), esc(row.state), row.rows_out ?? "", esc(row.error),
    ]))}
  `;
}

async function dangerous(kind, dataset) {
  const date = ($("rel-date") && $("rel-date").value) || "";
  const ds = dataset || prompt("数据集（daily/valuation/moneyflow/auction/stocks→A组整批；index_daily→B组；或 reference）", "daily");
  if (!ds) return;
  const password = prompt("二次确认：输入管理密码");
  if (!password) return;
  const confirmWord = `${ds}:${date}`;
  const typed = prompt(`请输入确认词：${confirmWord}`);
  const path = kind === "rollback" ? "/admin/api/rollback" : "/admin/api/backfill";
  await api(path, {
    method: "POST",
    body: JSON.stringify({ dataset: ds, trade_date: date, password, confirm: typed }),
  });
  render();
}

boot();
