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

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

interface ChecklistGroup {
  titleDE: string;
  titleEN: string;
  items: ChecklistItem[];
}

interface Checklist {
  slug: string;
  titleDE: string;
  titleEN: string;
  descriptionDE: string;
  descriptionEN: string;
  regime: string;
  courtDE: string;
  courtEN: string;
  deadlineDE?: string;
  deadlineEN?: string;
  referenceDE?: string;
  referenceEN?: string;
  groups: ChecklistGroup[];
}

interface Instance {
  id: string;
  template_slug: string;
  name: string;
  project_id?: string | null;
  state: Record<string, boolean>;
  created_by: string;
  created_at: string;
  updated_at: string;
  // Slice C — snapshot of the template body + its version at create time.
  template_snapshot?: { groups: ChecklistGroup[] } | null;
  template_version?: number | null;
}

// Slice C — augmented Checklist with origin + version, returned by
// /api/checklists/{slug}.
interface ChecklistWithMeta extends Checklist {
  origin?: "static" | "authored";
  version?: number;
}

let template: Checklist | null = null;
let instance: Instance | null = null;

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

function itemKey(groupIdx: number, itemIdx: number): string {
  return `g${groupIdx}-i${itemIdx}`;
}

function instanceID(): string {
  // /checklisten/instances/{id}
  const parts = window.location.pathname.split("/").filter(Boolean);
  return parts[2] ?? "";
}

function totalItems(): number {
  if (!template) return 0;
  return template.groups.reduce((n, g) => n + g.items.length, 0);
}

function doneItems(): number {
  if (!instance) return 0;
  return Object.values(instance.state || {}).filter(Boolean).length;
}

async function loadInstance(): Promise<boolean> {
  const id = instanceID();
  if (!id) return false;
  const resp = await fetch(`/api/checklist-instances/${encodeURIComponent(id)}`);
  if (!resp.ok) return false;
  instance = await resp.json();
  if (instance && typeof instance.state !== "object") instance.state = {};
  return true;
}

async function loadTemplate(slug: string): Promise<boolean> {
  const resp = await fetch(`/api/checklists/${encodeURIComponent(slug)}`);
  if (!resp.ok) return false;
  template = await resp.json();
  return true;
}

async function bootstrap() {
  const loading = document.getElementById("instance-loading")!;
  const notfound = document.getElementById("instance-notfound")!;
  const body = document.getElementById("instance-body")!;

  const okInst = await loadInstance();
  if (!okInst || !instance) {
    loading.style.display = "none";
    notfound.style.display = "";
    document.title = t("checklisten.instance.notfound");
    return;
  }
  const okTpl = await loadTemplate(instance.template_slug);
  if (!okTpl || !template) {
    loading.style.display = "none";
    notfound.style.display = "";
    return;
  }
  loading.style.display = "none";
  body.style.display = "";

  // Back link goes to the template page.
  const back = document.getElementById("instance-back") as HTMLAnchorElement;
  back.href = `/checklists/${encodeURIComponent(instance.template_slug)}`;

  renderAll();
}

function renderAll() {
  if (!template || !instance) return;
  renderHeader();
  renderGroups();
  updateProgress();
}

function renderHeader() {
  if (!template || !instance) return;
  const isEN = getLang() === "en";
  const tplTitle = isEN ? template.titleEN : template.titleDE;
  const court = isEN ? template.courtEN : template.courtDE;
  const deadline = isEN ? template.deadlineEN : template.deadlineDE;
  const reference = isEN ? template.referenceEN : template.referenceDE;

  document.title = `${instance.name} — Paliad`;
  (document.getElementById("instance-name-display") as HTMLElement).textContent = instance.name;
  (document.getElementById("instance-name-edit") as HTMLInputElement).value = instance.name;
  (document.getElementById("instance-template-title") as HTMLElement).textContent = tplTitle;

  const courtLabel = isEN ? "Court / Authority" : "Gericht / Behörde";
  const deadlineLabel = isEN ? "Deadline" : "Deadline";
  const refLabel = isEN ? "Reference" : "Rechtsgrundlage";
  const regimeLabel = isEN ? "Regime" : "Bereich";

  const parts: string[] = [];
  parts.push(`<div class="checklist-meta-item"><dt>${regimeLabel}</dt><dd><span class="checklist-regime checklist-regime-${esc(template.regime)}">${esc(template.regime)}</span></dd></div>`);
  parts.push(`<div class="checklist-meta-item"><dt>${courtLabel}</dt><dd>${esc(court)}</dd></div>`);
  if (deadline) {
    parts.push(`<div class="checklist-meta-item"><dt>${deadlineLabel}</dt><dd>${esc(deadline)}</dd></div>`);
  }
  if (reference) {
    parts.push(`<div class="checklist-meta-item"><dt>${refLabel}</dt><dd>${esc(reference)}</dd></div>`);
  }
  if (instance.project_id) {
    const akteLabel = isEN ? "Project" : "Projekt";
    parts.push(`<div class="checklist-meta-item"><dt>${akteLabel}</dt><dd><a href="/projects/${esc(instance.project_id)}">${t("checklisten.instance.akte.open") || "Öffnen"}</a></dd></div>`);
  }
  document.getElementById("instance-meta")!.innerHTML = parts.join("");
  renderOutdatedBadge();
}

// Slice C — show an "outdated" badge when the live template has a
// version > the instance's snapshot version. Both values must be
// non-null for the comparison to be meaningful (pre-Slice-C instances
// have NULL template_version; static templates always have version=1
// and never bump).
function renderOutdatedBadge() {
  const slot = document.getElementById("instance-outdated-slot");
  if (!slot || !instance || !template) return;
  const tplMeta = template as ChecklistWithMeta;
  const instVersion = instance.template_version;
  const tplVersion = tplMeta.version;
  if (
    instVersion == null ||
    tplVersion == null ||
    tplMeta.origin !== "authored" ||
    tplVersion <= instVersion
  ) {
    slot.innerHTML = "";
    return;
  }
  const badge = esc(t("checklisten.instance.outdated.badge"));
  const note = esc(
    t("checklisten.instance.outdated.note")
      .replace("{from}", String(instVersion))
      .replace("{to}", String(tplVersion)),
  );
  const action = esc(t("checklisten.instance.outdated.diff"));
  slot.innerHTML = `<div class="instance-outdated-banner">
    <span class="instance-outdated-badge">${badge}</span>
    <span class="instance-outdated-note">${note}</span>
    <button type="button" class="btn-small" id="btn-show-diff">${action}</button>
  </div>`;
  document.getElementById("btn-show-diff")!.addEventListener("click", openDiffModal);
}

// Shallow diff between two checklist bodies. Compares item label/note/
// rule pairs grouped by section title. Items with the same group title
// + same label are matched; differences in note/rule are flagged
// 'changed'. Items present only in snapshot are 'removed'; items only
// in current are 'added'.
function diffBodies(snapshot: { groups: ChecklistGroup[] } | null | undefined, current: ChecklistGroup[]):
  { added: string[]; removed: string[]; changed: string[] } {
  const added: string[] = [];
  const removed: string[] = [];
  const changed: string[] = [];
  const oldGroups = snapshot?.groups ?? [];
  const oldMap: Record<string, ChecklistItem> = {};
  for (const g of oldGroups) {
    for (const it of g.items) {
      const key = `${g.titleDE || g.titleEN}::${it.labelDE || it.labelEN}`;
      oldMap[key] = it;
    }
  }
  const newMap: Record<string, ChecklistItem> = {};
  for (const g of current) {
    for (const it of g.items) {
      const key = `${g.titleDE || g.titleEN}::${it.labelDE || it.labelEN}`;
      newMap[key] = it;
      if (!(key in oldMap)) {
        added.push(it.labelDE || it.labelEN);
      } else {
        const o = oldMap[key];
        if ((o.noteDE || o.noteEN || "") !== (it.noteDE || it.noteEN || "") ||
            (o.rule || "") !== (it.rule || "")) {
          changed.push(it.labelDE || it.labelEN);
        }
      }
    }
  }
  for (const key in oldMap) {
    if (!(key in newMap)) {
      const labelParts = key.split("::");
      removed.push(labelParts[1] || key);
    }
  }
  return { added, removed, changed };
}

function openDiffModal() {
  if (!template || !instance) return;
  const modal = document.getElementById("instance-diff-modal")!;
  const body = document.getElementById("instance-diff-body")!;
  const diff = diffBodies(instance.template_snapshot, template.groups);
  const empty = diff.added.length === 0 && diff.removed.length === 0 && diff.changed.length === 0;
  if (empty) {
    body.innerHTML = `<p class="entity-events-empty">${esc(t("checklisten.instance.diff.empty"))}</p>`;
  } else {
    const section = (label: string, klass: string, items: string[]) => {
      if (items.length === 0) return "";
      return `<section class="instance-diff-section ${klass}">
        <h3>${esc(label)}</h3>
        <ul>${items.map((s) => `<li>${esc(s)}</li>`).join("")}</ul>
      </section>`;
    };
    body.innerHTML = [
      section(t("checklisten.instance.diff.added"), "instance-diff-added", diff.added),
      section(t("checklisten.instance.diff.removed"), "instance-diff-removed", diff.removed),
      section(t("checklisten.instance.diff.changed"), "instance-diff-changed", diff.changed),
    ].join("");
  }
  modal.style.display = "flex";
}

function initDiffModal() {
  const modal = document.getElementById("instance-diff-modal");
  if (!modal) return;
  const close = () => { modal.style.display = "none"; };
  document.getElementById("instance-diff-close")?.addEventListener("click", close);
  document.getElementById("instance-diff-close-bottom")?.addEventListener("click", close);
  modal.addEventListener("click", (e) => { if (e.target === e.currentTarget) close(); });
}

function renderGroups() {
  if (!template || !instance) return;
  const isEN = getLang() === "en";
  const container = document.getElementById("checklist-groups")!;
  const state = instance.state || {};

  container.innerHTML = template.groups.map((g, gi) => {
    const groupTitle = isEN ? g.titleEN : g.titleDE;
    const items = g.items.map((item, ii) => {
      const key = itemKey(gi, ii);
      const checked = !!state[key];
      const label = isEN ? item.labelEN : item.labelDE;
      const note = isEN ? item.noteEN : item.noteDE;
      const rule = item.rule;

      const noteHTML = note ? `<p class="checklist-item-note">${esc(note)}</p>` : "";
      const ruleHTML = rule ? `<span class="checklist-item-rule">${esc(rule)}</span>` : "";

      return `<li class="checklist-item${checked ? " checked" : ""}" data-key="${key}">
        <label class="checklist-item-label">
          <input type="checkbox" class="checklist-checkbox" data-key="${key}"${checked ? " checked" : ""} />
          <span class="checklist-item-body">
            <span class="checklist-item-row">
              <span class="checklist-item-text">${esc(label)}</span>
              ${ruleHTML}
            </span>
            ${noteHTML}
          </span>
        </label>
      </li>`;
    }).join("");

    return `<section class="checklist-group">
      <h2 class="checklist-group-title">${esc(groupTitle)}</h2>
      <ol class="checklist-list">${items}</ol>
    </section>`;
  }).join("");

  container.querySelectorAll<HTMLInputElement>(".checklist-checkbox").forEach((cb) => {
    cb.addEventListener("change", () => {
      if (!instance) return;
      const key = cb.dataset.key!;
      instance.state[key] = cb.checked;
      const li = cb.closest(".checklist-item");
      if (li) li.classList.toggle("checked", cb.checked);
      updateProgress();
      void patchState({ [key]: cb.checked });
    });
  });
}

function updateProgress() {
  const total = totalItems();
  const done = doneItems();
  const pct = total === 0 ? 0 : Math.round((done / total) * 100);
  const fill = document.getElementById("progress-fill");
  if (fill) (fill as HTMLElement).style.width = `${pct}%`;
  const label = document.getElementById("progress-label");
  if (label) {
    const doneLabel = getLang() === "en" ? "done" : "erledigt";
    label.textContent = `${done} / ${total} ${doneLabel}`;
  }
}

async function patchState(patch: Record<string, boolean>) {
  if (!instance) return;
  try {
    const resp = await fetch(`/api/checklist-instances/${encodeURIComponent(instance.id)}`, {
      method: "PATCH",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ state: patch }),
    });
    if (!resp.ok) {
      console.warn("patchState failed", resp.status);
      // Revert local state on server failure.
      for (const k of Object.keys(patch)) instance.state[k] = !patch[k];
      renderGroups();
      updateProgress();
    }
  } catch (e) {
    console.warn("patchState error", e);
  }
}

function initReset() {
  const btn = document.getElementById("btn-reset");
  if (!btn) return;
  btn.addEventListener("click", async () => {
    if (!instance) return;
    const ok = confirm(t("checklisten.reset.confirm"));
    if (!ok) return;
    try {
      const resp = await fetch(`/api/checklist-instances/${encodeURIComponent(instance.id)}/reset`, {
        method: "POST",
      });
      if (!resp.ok) {
        alert(t("checklisten.reset.error"));
        return;
      }
      const updated = await resp.json() as Instance;
      instance = updated;
      if (typeof instance.state !== "object" || instance.state === null) instance.state = {};
      renderGroups();
      updateProgress();
    } catch {
      alert(t("checklisten.reset.error"));
    }
  });
}

function initPrint() {
  const btn = document.getElementById("btn-print");
  if (!btn) return;
  btn.addEventListener("click", () => window.print());
}

function initRename() {
  const display = document.getElementById("instance-name-display") as HTMLElement;
  const editInput = document.getElementById("instance-name-edit") as HTMLInputElement;
  const editBtn = document.getElementById("instance-rename-btn") as HTMLButtonElement;
  const saveBtn = document.getElementById("instance-name-save") as HTMLButtonElement;
  if (!display || !editInput || !editBtn || !saveBtn) return;

  const enterEdit = () => {
    if (!instance) return;
    editInput.value = instance.name;
    display.style.display = "none";
    editBtn.style.display = "none";
    editInput.style.display = "";
    saveBtn.style.display = "";
    editInput.focus();
    editInput.select();
  };
  const exitEdit = () => {
    display.style.display = "";
    editBtn.style.display = "";
    editInput.style.display = "none";
    saveBtn.style.display = "none";
  };

  editBtn.addEventListener("click", enterEdit);
  saveBtn.addEventListener("click", async () => {
    if (!instance) return;
    const newName = editInput.value.trim();
    if (!newName || newName === instance.name) {
      exitEdit();
      return;
    }
    try {
      const resp = await fetch(`/api/checklist-instances/${encodeURIComponent(instance.id)}`, {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ name: newName }),
      });
      if (!resp.ok) {
        alert(t("checklisten.instance.rename.error"));
        return;
      }
      instance = await resp.json();
      renderHeader();
      exitEdit();
    } catch {
      alert(t("checklisten.instance.rename.error"));
    }
  });
  editInput.addEventListener("keydown", (e) => {
    if (e.key === "Enter") { e.preventDefault(); saveBtn.click(); }
    if (e.key === "Escape") { e.preventDefault(); exitEdit(); }
  });
}

function initFeedback() {
  const modal = document.getElementById("feedback-modal")!;
  const form = document.getElementById("feedback-form")!;
  const msg = document.getElementById("feedback-msg")!;

  document.getElementById("btn-feedback")!.addEventListener("click", () => {
    msg.textContent = "";
    msg.className = "form-msg";
    modal.style.display = "flex";
  });

  document.getElementById("modal-close")!.addEventListener("click", () => { modal.style.display = "none"; });
  document.getElementById("modal-cancel")!.addEventListener("click", () => { modal.style.display = "none"; });
  modal.addEventListener("click", (e) => { if (e.target === e.currentTarget) modal.style.display = "none"; });

  form.addEventListener("submit", async (e) => {
    e.preventDefault();
    if (!template) return;
    const submitBtn = form.querySelector(".btn-submit") as HTMLButtonElement;
    const payload = {
      feedback_type: (document.getElementById("feedback-type") as HTMLSelectElement).value,
      checklist: template.slug,
      message: (document.getElementById("feedback-message") as HTMLTextAreaElement).value.trim(),
    };
    if (!payload.message) {
      msg.textContent = t("checklisten.feedback.error.required");
      msg.className = "form-msg form-msg-error";
      return;
    }
    submitBtn.disabled = true;
    try {
      const resp = await fetch("/api/checklists/feedback", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(payload),
      });
      if (!resp.ok) {
        msg.textContent = t("checklisten.feedback.error.generic");
        msg.className = "form-msg form-msg-error";
        return;
      }
      msg.textContent = t("checklisten.feedback.success");
      msg.className = "form-msg form-msg-success";
      (document.getElementById("feedback-message") as HTMLTextAreaElement).value = "";
      setTimeout(() => { modal.style.display = "none"; }, 1500);
    } catch {
      msg.textContent = t("checklisten.feedback.error.generic");
      msg.className = "form-msg form-msg-error";
    } finally {
      submitBtn.disabled = false;
    }
  });
}

document.addEventListener("DOMContentLoaded", () => {
  initI18n();
  initSidebar();
  initReset();
  initPrint();
  initRename();
  initFeedback();
  initDiffModal();
  onLangChange(renderAll);
  void bootstrap();
});
