// Authoring wizard for paliad.checklists. Serves both /checklists/new
// (create) and /checklists/templates/{slug}/edit (edit). The HTML bundle is the
// same; this client reads location.pathname to decide which mode to
// boot into.

import { initI18n, t } from "./i18n";
import { initSidebar } from "./sidebar";

interface Item {
  labelDE: string;
  labelEN: string;
  noteDE?: string;
  noteEN?: string;
  rule?: string;
}

interface Group {
  titleDE: string;
  titleEN: string;
  items: Item[];
}

interface Checklist {
  id: string;
  slug: string;
  title: string;
  description: string;
  regime: string;
  court: string;
  reference: string;
  deadline: string;
  lang: string;
  visibility: string;
  body: { groups: Group[] };
}

function esc(s: string): string {
  const d = document.createElement("div");
  d.textContent = s;
  return d.innerHTML;
}

function escAttr(s: string): string {
  return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;");
}

function detectMode(): { mode: "create" | "edit"; slug?: string } {
  const path = window.location.pathname;
  if (path === "/checklists/new") {
    return { mode: "create" };
  }
  const m = path.match(/^\/checklists\/templates\/([^/]+)\/edit$/);
  if (m) {
    return { mode: "edit", slug: m[1] };
  }
  return { mode: "create" };
}

let groups: Group[] = [];

function renderGroups() {
  const container = document.getElementById("groups-container")!;
  if (groups.length === 0) {
    // Seed with a single empty group + item so the user has something
    // to fill out rather than a blank canvas.
    groups = [{ titleDE: "", titleEN: "", items: [{ labelDE: "", labelEN: "" }] }];
  }
  container.innerHTML = groups.map((g, gi) => {
    const itemsHTML = g.items.map((it, ii) => {
      return `<div class="author-item" data-gi="${gi}" data-ii="${ii}">
        <div class="form-row">
          <label class="form-label">${esc(t("checklisten.author.item.label"))}</label>
          <input class="form-input" data-field="label" value="${escAttr(it.labelDE || "")}" />
        </div>
        <div class="form-grid form-grid-2">
          <div class="form-row">
            <label class="form-label">${esc(t("checklisten.author.item.note"))}</label>
            <input class="form-input" data-field="note" value="${escAttr(it.noteDE || "")}" />
          </div>
          <div class="form-row">
            <label class="form-label">${esc(t("checklisten.author.item.rule"))}</label>
            <input class="form-input" data-field="rule" value="${escAttr(it.rule || "")}" />
          </div>
        </div>
        <button type="button" class="btn btn-small btn-danger" data-action="remove-item">${esc(t("checklisten.author.item.remove"))}</button>
      </div>`;
    }).join("");
    return `<div class="author-group" data-gi="${gi}">
      <div class="form-row">
        <label class="form-label">${esc(t("checklisten.author.group.title"))}</label>
        <input class="form-input" data-field="group-title" value="${escAttr(g.titleDE || "")}" />
      </div>
      <div class="author-items">${itemsHTML}</div>
      <div class="author-group-actions">
        <button type="button" class="btn btn-small" data-action="add-item">${esc(t("checklisten.author.item.add"))}</button>
        <button type="button" class="btn btn-small btn-danger" data-action="remove-group">${esc(t("checklisten.author.group.remove"))}</button>
      </div>
    </div>`;
  }).join("");

  // Wire input changes back into the data array.
  container.querySelectorAll<HTMLInputElement>(".author-group > .form-row input[data-field=group-title]").forEach((input) => {
    const groupDiv = input.closest<HTMLElement>(".author-group")!;
    const gi = parseInt(groupDiv.dataset.gi!, 10);
    input.addEventListener("input", () => {
      groups[gi].titleDE = input.value;
      groups[gi].titleEN = input.value; // single-language for Slice A
    });
  });

  container.querySelectorAll<HTMLDivElement>(".author-item").forEach((itemDiv) => {
    const gi = parseInt(itemDiv.dataset.gi!, 10);
    const ii = parseInt(itemDiv.dataset.ii!, 10);
    itemDiv.querySelectorAll<HTMLInputElement>("input[data-field]").forEach((input) => {
      input.addEventListener("input", () => {
        const field = input.dataset.field!;
        if (field === "label") {
          groups[gi].items[ii].labelDE = input.value;
          groups[gi].items[ii].labelEN = input.value;
        } else if (field === "note") {
          groups[gi].items[ii].noteDE = input.value || undefined;
          groups[gi].items[ii].noteEN = input.value || undefined;
        } else if (field === "rule") {
          groups[gi].items[ii].rule = input.value || undefined;
        }
      });
    });
    itemDiv.querySelector<HTMLButtonElement>("button[data-action=remove-item]")!.addEventListener("click", () => {
      groups[gi].items.splice(ii, 1);
      if (groups[gi].items.length === 0) {
        groups[gi].items.push({ labelDE: "", labelEN: "" });
      }
      renderGroups();
    });
  });

  container.querySelectorAll<HTMLButtonElement>("button[data-action=add-item]").forEach((btn) => {
    const groupDiv = btn.closest<HTMLElement>(".author-group")!;
    const gi = parseInt(groupDiv.dataset.gi!, 10);
    btn.addEventListener("click", () => {
      groups[gi].items.push({ labelDE: "", labelEN: "" });
      renderGroups();
    });
  });

  container.querySelectorAll<HTMLButtonElement>("button[data-action=remove-group]").forEach((btn) => {
    const groupDiv = btn.closest<HTMLElement>(".author-group")!;
    const gi = parseInt(groupDiv.dataset.gi!, 10);
    btn.addEventListener("click", () => {
      groups.splice(gi, 1);
      renderGroups();
    });
  });
}

function showError(msg: string) {
  const err = document.getElementById("author-error")!;
  err.textContent = msg;
  err.style.display = "";
  err.scrollIntoView({ behavior: "smooth", block: "center" });
}

function clearError() {
  const err = document.getElementById("author-error")!;
  err.textContent = "";
  err.style.display = "none";
}

function collectInput() {
  const title = (document.getElementById("title") as HTMLInputElement).value.trim();
  const description = (document.getElementById("description") as HTMLTextAreaElement).value.trim();
  const regime = (document.getElementById("regime") as HTMLSelectElement).value;
  const court = (document.getElementById("court") as HTMLInputElement).value.trim();
  const reference = (document.getElementById("reference") as HTMLInputElement).value.trim();
  const deadline = (document.getElementById("deadline") as HTMLInputElement).value.trim();
  const lang = (document.getElementById("lang") as HTMLSelectElement).value;
  const visibilityInput = document.querySelector<HTMLInputElement>("input[name=visibility]:checked");
  const visibility = visibilityInput?.value || "private";
  return { title, description, regime, court, reference, deadline, lang, visibility };
}

function validateGroups(): boolean {
  if (groups.length === 0) return false;
  let totalItems = 0;
  for (const g of groups) {
    if (!g.titleDE.trim()) return false;
    for (const it of g.items) {
      if (it.labelDE.trim()) totalItems += 1;
    }
  }
  return totalItems > 0;
}

function trimmedGroups(): Group[] {
  return groups
    .filter((g) => g.titleDE.trim() && g.items.some((it) => it.labelDE.trim()))
    .map((g) => ({
      titleDE: g.titleDE.trim(),
      titleEN: g.titleEN.trim(),
      items: g.items
        .filter((it) => it.labelDE.trim())
        .map((it) => ({
          labelDE: it.labelDE.trim(),
          labelEN: it.labelEN.trim(),
          noteDE: it.noteDE?.trim() || undefined,
          noteEN: it.noteEN?.trim() || undefined,
          rule: it.rule?.trim() || undefined,
        })),
    }));
}

async function loadEditTemplate(slug: string) {
  // Use /api/checklists/{slug} (catalog Find with visibility check) +
  // the mine list to ensure we have the editable fields. Templates the
  // caller doesn't own/admin will trip the PATCH gate later.
  const resp = await fetch(`/api/checklists/templates/mine`);
  if (!resp.ok) {
    showError(t("checklisten.author.error.notfound"));
    return;
  }
  const rows: Checklist[] = (await resp.json()) ?? [];
  const tpl = rows.find((r) => r.slug === slug);
  if (!tpl) {
    showError(t("checklisten.author.error.notfound"));
    return;
  }
  (document.getElementById("author-heading")!).textContent = t("checklisten.author.heading.edit");
  document.title = t("checklisten.author.title.edit");
  (document.getElementById("title") as HTMLInputElement).value = tpl.title;
  (document.getElementById("description") as HTMLTextAreaElement).value = tpl.description;
  (document.getElementById("regime") as HTMLSelectElement).value = tpl.regime;
  (document.getElementById("court") as HTMLInputElement).value = tpl.court;
  (document.getElementById("reference") as HTMLInputElement).value = tpl.reference;
  (document.getElementById("deadline") as HTMLInputElement).value = tpl.deadline;
  (document.getElementById("lang") as HTMLSelectElement).value = tpl.lang || "de";
  const visIn = document.querySelector<HTMLInputElement>(`input[name=visibility][value=${tpl.visibility}]`);
  if (visIn) visIn.checked = true;
  groups = (tpl.body?.groups || []).map((g) => ({
    titleDE: g.titleDE || "",
    titleEN: g.titleEN || g.titleDE || "",
    items: g.items.map((it) => ({
      labelDE: it.labelDE || "",
      labelEN: it.labelEN || it.labelDE || "",
      noteDE: it.noteDE,
      noteEN: it.noteEN,
      rule: it.rule,
    })),
  }));
  if (groups.length === 0) {
    groups = [{ titleDE: "", titleEN: "", items: [{ labelDE: "", labelEN: "" }] }];
  }
  renderGroups();
}

async function submitCreate() {
  clearError();
  const input = collectInput();
  if (!input.title) {
    showError(t("checklisten.author.error.title"));
    return;
  }
  if (!validateGroups()) {
    showError(t("checklisten.author.error.no_groups"));
    return;
  }
  const saveBtn = document.getElementById("author-save") as HTMLButtonElement;
  saveBtn.disabled = true;
  saveBtn.textContent = t("checklisten.author.saving");
  const body = JSON.stringify({ ...input, body: { groups: trimmedGroups() } });
  const resp = await fetch("/api/checklists/templates", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body,
  });
  saveBtn.disabled = false;
  saveBtn.textContent = t("checklisten.author.save");
  if (!resp.ok) {
    let msg = t("checklisten.author.error.generic");
    try {
      const j = await resp.json();
      if (j?.error) msg = j.error;
    } catch { /* keep generic */ }
    showError(msg);
    return;
  }
  const created: Checklist = await resp.json();
  window.location.href = `/checklists/${encodeURIComponent(created.slug)}`;
}

async function submitEdit(slug: string) {
  clearError();
  const input = collectInput();
  if (!input.title) {
    showError(t("checklisten.author.error.title"));
    return;
  }
  if (!validateGroups()) {
    showError(t("checklisten.author.error.no_groups"));
    return;
  }
  const saveBtn = document.getElementById("author-save") as HTMLButtonElement;
  saveBtn.disabled = true;
  saveBtn.textContent = t("checklisten.author.saving");
  const patch = {
    title: input.title,
    description: input.description,
    regime: input.regime,
    court: input.court,
    reference: input.reference,
    deadline: input.deadline,
    body: { groups: trimmedGroups() },
  };
  const resp = await fetch(`/api/checklists/templates/${encodeURIComponent(slug)}`, {
    method: "PATCH",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(patch),
  });
  // Visibility lives on its own endpoint so the audit row reflects the
  // distinct transition. Only call if it actually changed.
  if (resp.ok && input.visibility) {
    await fetch(`/api/checklists/templates/${encodeURIComponent(slug)}/visibility`, {
      method: "PATCH",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ visibility: input.visibility }),
    });
  }
  saveBtn.disabled = false;
  saveBtn.textContent = t("checklisten.author.save");
  if (!resp.ok) {
    let msg = t("checklisten.author.error.generic");
    try {
      const j = await resp.json();
      if (j?.error) msg = j.error;
    } catch { /* keep generic */ }
    showError(msg);
    return;
  }
  window.location.href = `/checklists/${encodeURIComponent(slug)}`;
}

document.addEventListener("DOMContentLoaded", () => {
  initI18n();
  initSidebar();
  renderGroups();

  document.getElementById("add-group")!.addEventListener("click", () => {
    groups.push({ titleDE: "", titleEN: "", items: [{ labelDE: "", labelEN: "" }] });
    renderGroups();
  });

  const { mode, slug } = detectMode();

  if (mode === "edit" && slug) {
    void loadEditTemplate(slug);
  }

  document.getElementById("author-form")!.addEventListener("submit", (e) => {
    e.preventDefault();
    if (mode === "edit" && slug) {
      void submitEdit(slug);
    } else {
      void submitCreate();
    }
  });
});
