const $ = (selector) => document.querySelector(selector);
const API_BASE = "/api/cms";
const MAX_UPLOAD_SIZE = 20 * 1024 * 1024;
let categories = [];
let editingSlug = null;
let editingStatus = "new-unsaved";
let dirty = false;
let previewTimer = null;
let previewRequest = 0;

async function api(path, options = {}) {
  const endpoint = path.startsWith("/") ? path : `/${path}`;
  const response = await fetch(`${API_BASE}${endpoint}`, {
    headers: { "Content-Type": "application/json" },
    ...options,
    body: options.body ? JSON.stringify(options.body) : undefined,
  });
  let data = {};
  try { data = await response.json(); } catch {}
  if (!response.ok) throw new Error(data.error || `请求失败（${response.status}）`);
  return data;
}

const show = (selector) => $(selector).classList.remove("hidden");
const hide = (selector) => $(selector).classList.add("hidden");
const refreshCaptcha = () => {
  $("#captcha-image").src = `${API_BASE}/captcha?t=${Date.now()}`;
  $("#captcha").value = "";
};

function showLogin() {
  show("#login");
  hide("#app");
  refreshCaptcha();
  $("#password").focus();
}

async function boot() {
  const session = await api("/session").catch(() => ({ authed: false }));
  if (session.authed) {
    hide("#login"); show("#app");
    await loadCategories();
    loadArticles();
  }
  else showLogin();
}

$("#captcha-image").addEventListener("click", refreshCaptcha);

$("#login-form").addEventListener("submit", async (event) => {
  event.preventDefault();
  $("#login-error").textContent = "";
  try {
    await api("/session", { method: "POST", body: { password: $("#password").value, captcha: $("#captcha").value } });
    $("#password").value = "";
    $("#captcha").value = "";
    hide("#login"); show("#app");
    await loadCategories();
    loadArticles();
  } catch (error) {
    $("#login-error").textContent = error.message;
    refreshCaptcha();
  }
});

$("#logout").addEventListener("click", async () => { await api("/session", { method: "DELETE" }); location.reload(); });

const statusMap = {
  "new-unsaved": ["尚未保存", "new-draft", "填写完成后先保存草稿，线上网站不会发生变化。"],
  "new-draft": ["新建未发布", "new-draft", "这篇文章目前只有草稿版本，发布后才会出现在官网。"],
  "edited-draft": ["修改未发布", "edited-draft", "草稿已经保存，官网仍在展示上一次发布的版本。"],
  live: ["已上线", "live", "当前编辑内容与官网展示的版本一致。"],
};

function applyStatus(element, status) {
  const [label, className] = statusMap[status] || statusMap["new-draft"];
  element.className = `status ${className}`;
  element.textContent = label;
}

async function loadArticles() {
  const articles = await api("/articles").catch((error) => { alert(error.message); return []; });
  const list = $("#article-list");
  list.innerHTML = "";
  const pending = articles.filter((item) => item.publishStatus !== "live").length;
  $("#pending-badge").textContent = `${pending} 篇草稿待发布`;
  $("#pending-badge").classList.toggle("hidden", pending === 0);
  if (!articles.length) { list.innerHTML = '<div class="empty">还没有文章，点击“新建文章”开始。</div>'; return; }
  for (const article of articles) {
    const card = document.createElement("article");
    card.className = "article-row";
    card.innerHTML = '<div class="article-summary"><h2></h2><p><span class="category"></span><span class="updated"></span><span class="status"></span></p></div><div class="row-actions"></div>';
    card.querySelector("h2").textContent = article.title;
    card.querySelector(".category").textContent = article.category;
    card.querySelector(".updated").textContent = `更新于 ${article.updated}`;
    applyStatus(card.querySelector(".status"), article.publishStatus);
    const actions = card.querySelector(".row-actions");
    const edit = listAction("编辑", "ghost small", () => openEditor(article.slug));
    const publish = listAction("发布", "primary small", () => publishFromList(article));
    publish.disabled = article.publishStatus === "live";
    publish.title = publish.disabled ? "文章当前已上线" : "发布到官网";
    actions.append(edit, publish, listMoreActions(article));
    list.append(card);
  }
}

function listAction(label, className, action) {
  const button = document.createElement("button");
  button.type = "button";
  button.className = className;
  button.textContent = label;
  button.onclick = action;
  return button;
}

function listMenuAction(label, className, action) {
  return listAction(label, `menu-action ${className}`.trim(), async (event) => {
    event.currentTarget.closest("details").open = false;
    await action();
  });
}

function listMoreActions(article) {
  const details = document.createElement("details");
  details.className = "more-actions row-more-actions";
  const summary = document.createElement("summary");
  summary.textContent = "更多";
  summary.setAttribute("aria-label", `${article.title}的更多操作`);
  const menu = document.createElement("div");
  menu.className = "action-menu";
  if (article.publishStatus === "edited-draft") {
    menu.append(listMenuAction("放弃未发布修改", "", () => discardFromList(article)));
  }
  if (["live", "edited-draft"].includes(article.publishStatus)) {
    menu.append(listMenuAction("下架文章", "danger", () => unpublishFromList(article)));
  }
  menu.append(listMenuAction("删除文章", "danger", () => deleteFromList(article)));
  details.append(summary, menu);
  details.addEventListener("toggle", () => {
    if (!details.open) return;
    document.querySelectorAll(".row-more-actions[open]").forEach((item) => {
      if (item !== details) item.open = false;
    });
  });
  return details;
}

async function publishFromList(article) {
  try {
    await triggerBuild(`/articles/${article.slug}/publish`);
    await loadArticles();
  } catch {}
}

async function discardFromList(article) {
  if (!confirm(`确定放弃《${article.title}》未发布的修改，恢复为当前线上版本吗？`)) return;
  try {
    await api(`/articles/${article.slug}/draft`, { method: "DELETE" });
    await loadArticles();
  } catch (error) { alert(error.message); }
}

async function unpublishFromList(article) {
  const detail = article.publishStatus === "edited-draft" ? "未发布的修改会继续保留为草稿。" : "文章内容会继续保留为草稿。";
  if (!confirm(`确定将《${article.title}》从官网下架吗？${detail}`)) return;
  try {
    await triggerBuild(`/articles/${article.slug}/unpublish`, { action: "下架" });
    await loadArticles();
  } catch {}
}

async function deleteFromList(article) {
  const prompt = article.publishStatus === "new-draft"
    ? `确定彻底删除草稿《${article.title}》吗？删除后无法恢复。`
    : `确定彻底删除《${article.title}》吗？线上版本和草稿都会删除，且无法恢复。`;
  if (!confirm(prompt)) return;
  try {
    await triggerBuild(`/articles/${article.slug}`, { action: "删除", method: "DELETE" });
    await loadArticles();
  } catch {}
}

function fillCategories(selected) {
  const current = selected || $("#category").value || categories[0] || "";
  const options = $("#category-options");
  options.innerHTML = "";
  categories.forEach((name) => {
    const option = document.createElement("button");
    option.type = "button";
    option.className = "select-option";
    option.dataset.value = name;
    option.setAttribute("role", "option");
    option.setAttribute("aria-selected", String(name === current));
    option.innerHTML = '<span></span><span class="option-check" aria-hidden="true">✓</span>';
    option.querySelector("span").textContent = name;
    option.addEventListener("click", () => {
      selectCategory(name, true);
      closeCategoryMenu();
    });
    options.append(option);
  });
  selectCategory(categories.includes(current) ? current : categories[0] || "", false);
}

function selectCategory(name, markDirty) {
  $("#category").value = name;
  $("#category-value").textContent = name || "请选择分类";
  $("#category-options").querySelectorAll(".select-option").forEach((option) => {
    option.setAttribute("aria-selected", String(option.dataset.value === name));
  });
  if (markDirty) dirty = true;
}

function closeCategoryMenu() {
  $("#category-menu").classList.add("hidden");
  $("#category-trigger").setAttribute("aria-expanded", "false");
  $("#category-select").classList.remove("open");
}

function toggleCategoryMenu() {
  const opening = $("#category-menu").classList.contains("hidden");
  if (!opening) return closeCategoryMenu();
  $("#category-menu").classList.remove("hidden");
  $("#category-trigger").setAttribute("aria-expanded", "true");
  $("#category-select").classList.add("open");
  $("#category-error").textContent = "";
}

$("#category-trigger").addEventListener("click", (event) => { event.stopPropagation(); toggleCategoryMenu(); });
$("#category-menu").addEventListener("click", (event) => event.stopPropagation());
document.addEventListener("click", closeCategoryMenu);
document.addEventListener("click", (event) => {
  document.querySelectorAll(".row-more-actions[open]").forEach((details) => {
    if (!details.contains(event.target)) details.open = false;
  });
});
document.addEventListener("keydown", (event) => { if (event.key === "Escape") closeCategoryMenu(); });

async function createCategory() {
  const input = $("#new-category");
  const name = input.value.trim();
  $("#category-error").textContent = "";
  try {
    await triggerBuild("/categories", { action: "添加分类", body: { name } });
    await loadCategories();
    input.value = "";
    fillCategories(name);
    dirty = true;
    closeCategoryMenu();
    if (!$("#category-modal").classList.contains("hidden")) await loadCategoryManager();
  } catch (error) { $("#category-error").textContent = error.message; }
}

$("#add-category").addEventListener("click", createCategory);
$("#new-category").addEventListener("keydown", (event) => {
  if (event.key !== "Enter") return;
  event.preventDefault();
  createCategory();
});

async function loadCategories() {
  const result = await api("/categories");
  categories = result.categories;
  fillCategories($("#category").value);
  return result;
}

async function loadCategoryManager() {
  const result = await loadCategories();
  renderCategoryManager(result.stats || []);
}

function clearCategoryPanels() {
  $("#category-manager-list").querySelectorAll(".category-inline-panel").forEach((panel) => panel.remove());
}

function categoryPanel(row, text) {
  clearCategoryPanels();
  const panel = document.createElement("div");
  panel.className = "category-inline-panel";
  const note = document.createElement("p");
  note.textContent = text;
  panel.append(note);
  row.append(panel);
  return panel;
}

async function runCategoryBuild(action, method, body) {
  $("#manager-category-error").textContent = "";
  try {
    await triggerBuild("/categories", { action, method, body });
    await loadCategoryManager();
    await loadArticles();
  } catch (error) {
    $("#manager-category-error").textContent = error.message;
    await loadCategoryManager().catch(() => {});
  }
}

function showRenameCategory(row, stat) {
  const panel = categoryPanel(row, `重命名后，${stat.count} 篇文章会同步更新分类。`);
  const form = document.createElement("div");
  form.className = "category-rename-form";
  const input = document.createElement("input");
  input.maxLength = 20;
  input.value = stat.name;
  input.setAttribute("aria-label", `重命名 ${stat.name}`);
  const save = document.createElement("button");
  save.type = "button";
  save.className = "primary";
  save.textContent = "保存名称";
  const cancel = document.createElement("button");
  cancel.type = "button";
  cancel.className = "ghost";
  cancel.textContent = "取消";
  save.onclick = () => {
    const name = input.value.trim();
    if (!name || name === stat.name) return clearCategoryPanels();
    runCategoryBuild("更新分类", "PATCH", { current: stat.name, name });
  };
  cancel.onclick = clearCategoryPanels;
  input.addEventListener("keydown", (event) => {
    if (event.key === "Enter") { event.preventDefault(); save.click(); }
    if (event.key === "Escape") clearCategoryPanels();
  });
  form.append(input, save, cancel);
  panel.append(form);
  input.focus();
  input.select();
}

function showDeleteCategory(row, stat) {
  const panel = categoryPanel(
    row,
    stat.count ? `该分类下有 ${stat.count} 篇文章，请选择删除后要迁移到的分类。` : "该分类下没有文章，可以直接删除。",
  );
  const actions = document.createElement("div");
  actions.className = stat.count ? "replacement-options" : "category-inline-actions";
  const choices = stat.count ? categories.filter((name) => name !== stat.name) : [""];
  choices.forEach((replacement) => {
    const button = document.createElement("button");
    button.type = "button";
    button.className = stat.count ? "" : "confirm-danger";
    button.textContent = stat.count ? `迁移到“${replacement}”并删除` : "确认删除分类";
    button.onclick = () => runCategoryBuild("删除分类", "DELETE", { name: stat.name, replacement });
    actions.append(button);
  });
  const cancel = document.createElement("button");
  cancel.type = "button";
  cancel.className = "ghost";
  cancel.textContent = "取消";
  cancel.onclick = clearCategoryPanels;
  actions.append(cancel);
  panel.append(actions);
}

function renderCategoryManager(stats) {
  const list = $("#category-manager-list");
  list.innerHTML = "";
  stats.forEach((stat) => {
    const row = document.createElement("div");
    row.className = "category-manager-row";
    const main = document.createElement("div");
    main.className = "category-row-main";
    const name = document.createElement("div");
    name.className = "category-row-name";
    const strong = document.createElement("strong");
    strong.textContent = stat.name;
    const count = document.createElement("span");
    count.textContent = stat.count ? `${stat.count} 篇文章` : "暂无文章";
    name.append(strong, count);
    const actions = document.createElement("div");
    actions.className = "category-row-actions";
    const rename = document.createElement("button");
    rename.type = "button";
    rename.className = "ghost";
    rename.textContent = "重命名";
    rename.onclick = () => showRenameCategory(row, stat);
    const remove = document.createElement("button");
    remove.type = "button";
    remove.className = "ghost danger";
    remove.textContent = "删除";
    remove.disabled = categories.length <= 1;
    remove.title = remove.disabled ? "至少需要保留一个分类" : "删除分类";
    remove.onclick = () => showDeleteCategory(row, stat);
    actions.append(rename, remove);
    main.append(name, actions);
    row.append(main);
    list.append(row);
  });
}

async function openCategoryManager() {
  $("#manager-category-error").textContent = "";
  show("#category-modal");
  try { await loadCategoryManager(); }
  catch (error) { $("#manager-category-error").textContent = error.message; }
}

$("#manage-categories").addEventListener("click", openCategoryManager);
$("#close-category-modal").addEventListener("click", () => hide("#category-modal"));
$("#manager-add-category").addEventListener("click", async () => {
  const input = $("#manager-new-category");
  const name = input.value.trim();
  $("#manager-category-error").textContent = "";
  try {
    await triggerBuild("/categories", { action: "添加分类", body: { name } });
    input.value = "";
    await loadCategoryManager();
  } catch (error) { $("#manager-category-error").textContent = error.message; }
});
$("#manager-new-category").addEventListener("keydown", (event) => {
  if (event.key === "Enter") { event.preventDefault(); $("#manager-add-category").click(); }
});

function setView(editing) {
  $("#list-view").classList.toggle("hidden", editing);
  $("#edit-view").classList.toggle("hidden", !editing);
}

function setEditorStatus(status) {
  editingStatus = status;
  applyStatus($("#editor-status"), status);
  $("#version-note").textContent = statusMap[status]?.[2] || "";
  const persisted = status !== "new-unsaved";
  $("#more-actions").classList.toggle("hidden", !persisted);
  $("#more-actions").open = false;
  $("#discard").classList.toggle("hidden", status !== "edited-draft");
  $("#unpublish").classList.toggle("hidden", !["live", "edited-draft"].includes(status));
  $("#delete-article").classList.toggle("hidden", !persisted);
}

async function openEditor(slug) {
  editingSlug = slug;
  dirty = false;
  fillCategories();
  $("#preview").innerHTML = "";
  $("#message").textContent = "";
  $("#upload-status").textContent = "";
  if (slug) {
    const article = await api(`/articles/${slug}`);
    $("#edit-heading").textContent = "编辑文章";
    $("#title").value = article.title;
    fillCategories(article.category);
    $("#body").value = article.body;
    setEditorStatus(article.publishStatus);
  } else {
    $("#edit-heading").textContent = "新建文章";
    $("#title").value = "";
    $("#body").value = "";
    setEditorStatus("new-unsaved");
  }
  setView(true);
  schedulePreview(0);
  $("#title").focus();
}

$("#new-article").addEventListener("click", () => openEditor(null));
$("#back").addEventListener("click", () => {
  if (dirty && !confirm("还有未保存的内容，确定返回文章列表吗？")) return;
  setView(false);
  loadArticles();
});

function payload() {
  return {
    title: $("#title").value.trim(),
    category: $("#category").value,
    body: $("#body").value,
  };
}

async function save() {
  const result = editingSlug
    ? await api(`/articles/${editingSlug}`, { method: "PUT", body: payload() })
    : await api("/articles", { method: "POST", body: payload() });
  editingSlug = result.slug;
  dirty = false;
  setEditorStatus(result.publishStatus);
  return result.slug;
}

$("#edit-form").addEventListener("submit", async (event) => {
  event.preventDefault();
  $("#message").textContent = "正在保存…";
  try {
    await save();
    $("#message").textContent = editingStatus === "live" ? "内容与线上版本一致。" : "草稿已保存，线上版本没有改变。";
  } catch (error) { $("#message").textContent = error.message; }
});

$("#publish").addEventListener("click", async () => {
  $("#message").textContent = "正在保存草稿…";
  try {
    const slug = await save();
    await triggerBuild(`/articles/${slug}/publish`);
    setEditorStatus("live");
    $("#message").textContent = "发布成功，官网已更新。";
  } catch (error) { $("#message").textContent = error.message; }
});

$("#discard").addEventListener("click", async () => {
  if (!editingSlug) return;
  if (!confirm("确定放弃未发布的修改，恢复为当前线上版本吗？")) return;
  try {
    const result = await api(`/articles/${editingSlug}/draft`, { method: "DELETE" });
    dirty = false;
    if (result.removed) { setView(false); loadArticles(); }
    else await openEditor(editingSlug);
  } catch (error) { $("#message").textContent = error.message; }
});

$("#unpublish").addEventListener("click", async () => {
  if (!editingSlug) return;
  const detail = editingStatus === "edited-draft" ? "未发布的修改会继续保留为草稿。" : "文章内容会继续保留为草稿。";
  if (!confirm(`确定将这篇文章从官网下架吗？${detail}`)) return;
  $("#more-actions").open = false;
  $("#message").textContent = "正在下架文章…";
  try {
    await triggerBuild(`/articles/${editingSlug}/unpublish`, { action: "下架" });
    setEditorStatus("new-draft");
    $("#message").textContent = "文章已下架，内容已保留为草稿。";
  } catch (error) { $("#message").textContent = error.message; }
});

$("#delete-article").addEventListener("click", async () => {
  if (!editingSlug) return;
  const prompt = editingStatus === "new-draft"
    ? "确定彻底删除这篇草稿吗？删除后无法恢复。"
    : "确定彻底删除这篇文章吗？线上版本和草稿都会删除，且无法恢复。";
  if (!confirm(prompt)) return;
  $("#more-actions").open = false;
  $("#message").textContent = "正在删除文章…";
  try {
    await triggerBuild(`/articles/${editingSlug}`, { action: "删除", method: "DELETE" });
    dirty = false;
    editingSlug = null;
    setView(false);
    await loadArticles();
  } catch (error) { $("#message").textContent = error.message; }
});

async function renderPreview() {
  const body = $("#body").value.trim();
  if (!body) { $("#preview").innerHTML = ""; return; }
  const request = ++previewRequest;
  try {
    const result = await api("/preview", { method: "POST", body: { body } });
    if (request === previewRequest) $("#preview").innerHTML = result.html;
  } catch {
    if (request === previewRequest) $("#preview").textContent = "预览暂时不可用";
  }
}

function schedulePreview(delay = 350) {
  clearTimeout(previewTimer);
  previewTimer = setTimeout(renderPreview, delay);
}

$("#title").addEventListener("input", () => { dirty = true; });
$("#body").addEventListener("input", () => { dirty = true; schedulePreview(); });

$("#upload-button").addEventListener("click", () => $("#file").click());
$("#file").addEventListener("change", async (event) => {
  const file = event.target.files?.[0];
  event.target.value = "";
  if (!file) return;
  if (file.size > MAX_UPLOAD_SIZE) {
    $("#upload-status").textContent = "图片不能超过 20MB";
    return;
  }
  $("#upload-status").textContent = "上传中…";
  try {
    const dataUrl = await new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(reader.result);
      reader.onerror = reject;
      reader.readAsDataURL(file);
    });
    const result = await api("/uploads", { method: "POST", body: { dataUrl } });
    const textarea = $("#body");
    const start = textarea.selectionStart;
    const markdown = `\n![${file.name}](${result.url})\n`;
    textarea.value = textarea.value.slice(0, start) + markdown + textarea.value.slice(textarea.selectionEnd);
    textarea.dispatchEvent(new Event("input"));
    $("#upload-status").textContent = "图片已插入";
  } catch (error) { $("#upload-status").textContent = error.message; }
});

async function triggerBuild(endpoint, { action = "发布", method = "POST", body } = {}) {
  show("#build-modal");
  hide("#close-modal");
  $("#build-title").textContent = `正在${action}…`;
  $("#build-log").textContent = "系统正在更新官网，请稍候。";
  try {
    await api(endpoint, { method, body });
  } catch (error) {
    $("#build-title").textContent = `${action}失败`;
    $("#build-log").textContent = error.message;
    show("#close-modal");
    throw error;
  }
  while (true) {
    await new Promise((resolve) => setTimeout(resolve, 1000));
    const state = await api("/build");
    if (state.status === "building") continue;
    if (state.ok) { hide("#build-modal"); return; }
    $("#build-title").textContent = `${action}失败`;
    $("#build-log").textContent = state.log || `${action}失败，请联系技术人员。`;
    show("#close-modal");
    throw new Error(`${action}失败，原文章已恢复，请检查操作日志。`);
  }
}

$("#close-modal").addEventListener("click", () => hide("#build-modal"));

boot();
