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

// admin-event-types.ts — moderation panel for paliad.event_types
// (t-paliad-089). Loads two tables: firm-wide (with archived toggle, bulk
// archive, merge) and private-pending-promotion (per-row promote button).

interface EventTypeRow {
  id: string;
  slug: string;
  label_de: string;
  label_en: string;
  category: string;
  jurisdiction?: string | null;
  description?: string;
  is_firm_wide: boolean;
  archived_at?: string | null;
  created_by?: string | null;
  created_at: string;
  updated_at: string;
  usage_count: number;
  author_display_name?: string | null;
}

let firmwide: EventTypeRow[] = [];
let priv: EventTypeRow[] = [];
let selected = new Set<string>();
let showArchived = false;
let searchQuery = "";

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

function fmtDate(iso: string): string {
  if (!iso) return "";
  const d = new Date(iso);
  if (Number.isNaN(d.getTime())) return iso;
  return d.toLocaleDateString();
}

function categoryLabel(cat: string): string {
  return tDyn(`event_types.cat.${cat}`) || cat;
}

function labelFor(row: EventTypeRow): string {
  // Show DE primary, EN as a small secondary line if it differs.
  return row.label_de;
}

function rowMatchesSearch(row: EventTypeRow): boolean {
  if (!searchQuery) return true;
  const q = searchQuery.toLowerCase();
  return (
    row.label_de.toLowerCase().includes(q) ||
    row.label_en.toLowerCase().includes(q) ||
    row.slug.toLowerCase().includes(q) ||
    (row.author_display_name ?? "").toLowerCase().includes(q)
  );
}

function showFeedback(msg: string, isError: boolean) {
  const el = document.getElementById("aet-feedback")!;
  el.textContent = msg;
  el.className = "form-msg " + (isError ? "form-msg-error" : "form-msg-ok");
  el.style.display = "block";
  if (!isError) {
    setTimeout(() => { el.style.display = "none"; }, 3500);
  }
}

async function loadFirmwide(): Promise<void> {
  const url = "/api/admin/event-types" + (showArchived ? "?include_archived=1" : "");
  const resp = await fetch(url);
  if (resp.status === 403) {
    showFeedback(t("admin.event_types.error.forbidden") || "Nur Admins.", true);
    firmwide = [];
    return;
  }
  if (!resp.ok) {
    firmwide = [];
    return;
  }
  firmwide = (await resp.json()) as EventTypeRow[];
}

async function loadPrivate(): Promise<void> {
  const resp = await fetch("/api/admin/event-types/private");
  if (!resp.ok) {
    priv = [];
    return;
  }
  priv = (await resp.json()) as EventTypeRow[];
}

function jurisdictionLabel(j: string | null | undefined): string {
  if (!j) return "—";
  if (j === "any") return tDyn("event_types.add.jurisdiction.any") || j;
  return j;
}

function renderFirmwideRow(row: EventTypeRow): string {
  const archived = !!row.archived_at;
  const checked = selected.has(row.id) ? " checked" : "";
  const labelEn = row.label_en && row.label_en !== row.label_de
    ? `<div class="admin-team-muted aet-label-en">${esc(row.label_en)}</div>`
    : "";
  const archivedBadge = archived
    ? `<span class="aet-archived-badge">${esc(t("admin.event_types.row.archived") || "Archiviert")}</span>`
    : "";
  const restoreBtn = archived
    ? `<button type="button" class="btn-link aet-restore" data-id="${esc(row.id)}" data-i18n="admin.event_types.action.restore">Wiederherstellen</button>`
    : `<button type="button" class="btn-link aet-archive" data-id="${esc(row.id)}" data-i18n="admin.event_types.action.archive">Archivieren</button>`;
  return `
    <tr data-row-id="${esc(row.id)}"${archived ? " class=\"aet-row-archived\"" : ""}>
      <td class="aet-col-check">
        ${archived ? "" : `<input type="checkbox" class="aet-row-check" data-id="${esc(row.id)}"${checked} />`}
      </td>
      <td class="entity-col-title">
        ${archivedBadge}
        <div>${esc(labelFor(row))}</div>
        ${labelEn}
        <div class="admin-team-muted aet-slug">${esc(row.slug)}</div>
      </td>
      <td>${esc(categoryLabel(row.category))}</td>
      <td>${esc(jurisdictionLabel(row.jurisdiction))}</td>
      <td>${row.author_display_name ? esc(row.author_display_name) : `<span class="admin-team-muted">${esc(t("admin.event_types.author.system") || "System")}</span>`}</td>
      <td class="entity-col-updated">${esc(fmtDate(row.created_at))}</td>
      <td>${row.usage_count}</td>
      <td class="admin-team-actions-cell">${restoreBtn}</td>
    </tr>`;
}

function renderPrivateRow(row: EventTypeRow): string {
  return `
    <tr data-row-id="${esc(row.id)}">
      <td class="entity-col-title">
        <div>${esc(row.label_de)}</div>
        ${row.label_en && row.label_en !== row.label_de ? `<div class="admin-team-muted aet-label-en">${esc(row.label_en)}</div>` : ""}
        <div class="admin-team-muted aet-slug">${esc(row.slug)}</div>
      </td>
      <td>${esc(categoryLabel(row.category))}</td>
      <td>${esc(jurisdictionLabel(row.jurisdiction))}</td>
      <td>${row.author_display_name ? esc(row.author_display_name) : `<span class="admin-team-muted">${esc(t("admin.event_types.author.unknown") || "Unbekannt")}</span>`}</td>
      <td>${row.usage_count}</td>
      <td class="admin-team-actions-cell">
        <button type="button" class="btn-primary btn-small aet-promote" data-id="${esc(row.id)}" data-i18n="admin.event_types.action.promote">Bef&ouml;rdern</button>
      </td>
    </tr>`;
}

function renderFirmwide() {
  const tbody = document.getElementById("aet-tbody")!;
  const empty = document.getElementById("aet-empty")!;
  const count = document.getElementById("aet-count")!;

  const filtered = firmwide.filter(rowMatchesSearch);
  count.textContent = `${filtered.length} / ${firmwide.length}`;

  if (filtered.length === 0) {
    tbody.innerHTML = "";
    empty.style.display = "block";
    updateBulkBar();
    return;
  }
  empty.style.display = "none";
  tbody.innerHTML = filtered.map(renderFirmwideRow).join("");
  attachFirmwideRowListeners();
  updateBulkBar();
}

function renderPrivate() {
  const tbody = document.getElementById("aet-private-tbody")!;
  const empty = document.getElementById("aet-private-empty")!;

  const filtered = priv.filter(rowMatchesSearch);
  if (filtered.length === 0) {
    tbody.innerHTML = "";
    empty.style.display = "block";
    return;
  }
  empty.style.display = "none";
  tbody.innerHTML = filtered.map(renderPrivateRow).join("");
  attachPrivateRowListeners();
}

function attachFirmwideRowListeners() {
  document.querySelectorAll<HTMLInputElement>(".aet-row-check").forEach((cb) => {
    cb.addEventListener("change", () => {
      const id = cb.dataset.id!;
      if (cb.checked) selected.add(id);
      else selected.delete(id);
      updateBulkBar();
    });
  });
  document.querySelectorAll<HTMLButtonElement>(".aet-archive").forEach((b) => {
    b.addEventListener("click", () => archiveOne(b.dataset.id!));
  });
  document.querySelectorAll<HTMLButtonElement>(".aet-restore").forEach((b) => {
    b.addEventListener("click", () => restoreOne(b.dataset.id!));
  });
}

function attachPrivateRowListeners() {
  document.querySelectorAll<HTMLButtonElement>(".aet-promote").forEach((b) => {
    b.addEventListener("click", () => promoteOne(b.dataset.id!));
  });
}

function updateBulkBar() {
  const bar = document.getElementById("aet-bulk-actions")!;
  const count = document.getElementById("aet-bulk-count")!;
  const mergeBtn = document.getElementById("aet-bulk-merge") as HTMLButtonElement;
  // Drop selections that no longer correspond to a visible live row.
  const liveIDs = new Set(firmwide.filter((r) => !r.archived_at).map((r) => r.id));
  for (const id of Array.from(selected)) {
    if (!liveIDs.has(id)) selected.delete(id);
  }
  if (selected.size === 0) {
    bar.style.display = "none";
    return;
  }
  bar.style.display = "flex";
  const tmpl = t("admin.event_types.bulk.count") || "{n} ausgewählt";
  count.textContent = tmpl.replace("{n}", String(selected.size));
  mergeBtn.disabled = selected.size < 2;
}

async function archiveOne(id: string) {
  const row = firmwide.find((r) => r.id === id);
  if (!row) return;
  const confirmMsg = (t("admin.event_types.confirm.archive") || "„{label}\" wirklich archivieren?").replace("{label}", row.label_de);
  if (!window.confirm(confirmMsg)) return;
  await bulkArchive([id]);
}

async function bulkArchiveSelected() {
  if (selected.size === 0) return;
  const tmpl = t("admin.event_types.confirm.bulk_archive") || "{n} Typen wirklich archivieren?";
  if (!window.confirm(tmpl.replace("{n}", String(selected.size)))) return;
  await bulkArchive(Array.from(selected));
}

async function bulkArchive(ids: string[]) {
  const resp = await fetch("/api/admin/event-types/archive", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ ids }),
  });
  if (!resp.ok) {
    const body = await resp.json().catch(() => ({ error: resp.statusText }));
    showFeedback(body.error || t("admin.event_types.feedback.archive_error") || "Archivierung fehlgeschlagen.", true);
    return;
  }
  const body = (await resp.json()) as { archived: number };
  selected.clear();
  showFeedback((t("admin.event_types.feedback.archived") || "{n} archiviert.").replace("{n}", String(body.archived)), false);
  await Promise.all([loadFirmwide(), loadPrivate()]);
  renderFirmwide();
  renderPrivate();
}

async function restoreOne(id: string) {
  const row = firmwide.find((r) => r.id === id);
  if (!row) return;
  const resp = await fetch(`/api/admin/event-types/${id}/restore`, { method: "POST" });
  if (!resp.ok) {
    const body = await resp.json().catch(() => ({ error: resp.statusText }));
    showFeedback(body.error || t("admin.event_types.feedback.restore_error") || "Wiederherstellung fehlgeschlagen.", true);
    return;
  }
  showFeedback(t("admin.event_types.feedback.restored") || "Wiederhergestellt.", false);
  await loadFirmwide();
  renderFirmwide();
}

async function promoteOne(id: string) {
  const row = priv.find((r) => r.id === id);
  if (!row) return;
  const confirmMsg = (t("admin.event_types.confirm.promote") || "„{label}\" firmenweit verfügbar machen?").replace("{label}", row.label_de);
  if (!window.confirm(confirmMsg)) return;
  const resp = await fetch(`/api/admin/event-types/${id}/promote`, { method: "POST" });
  if (!resp.ok) {
    const body = await resp.json().catch(() => ({ error: resp.statusText }));
    showFeedback(body.error || t("admin.event_types.feedback.promote_error") || "Beförderung fehlgeschlagen.", true);
    return;
  }
  showFeedback(t("admin.event_types.feedback.promoted") || "Befördert.", false);
  await Promise.all([loadFirmwide(), loadPrivate()]);
  renderFirmwide();
  renderPrivate();
}

function openMergeModal() {
  if (selected.size < 2) return;
  const candidates = firmwide.filter((r) => selected.has(r.id) && !r.archived_at);
  if (candidates.length < 2) return;

  // Suggest the highest-usage row as the default winner — preserves the most
  // junction rows untouched (they don't even need an INSERT, just the others
  // get redirected onto it).
  const initialWinner = candidates.slice().sort((a, b) => b.usage_count - a.usage_count)[0]!.id;

  const opts = document.getElementById("aet-merge-options")!;
  opts.innerHTML = candidates.map((r) => {
    const checked = r.id === initialWinner ? " checked" : "";
    return `
      <label class="aet-merge-option">
        <input type="radio" name="aet-merge-winner" value="${esc(r.id)}"${checked} />
        <div class="aet-merge-option-body">
          <div class="aet-merge-option-label">${esc(r.label_de)}</div>
          <div class="admin-team-muted aet-merge-option-meta">
            ${esc(categoryLabel(r.category))} · ${esc(jurisdictionLabel(r.jurisdiction))} · ${r.usage_count}&times;
          </div>
        </div>
      </label>`;
  }).join("");

  const msg = document.getElementById("aet-merge-msg")!;
  msg.textContent = "";
  msg.className = "form-msg";
  document.getElementById("aet-merge-modal")!.style.display = "flex";
}

function closeMergeModal() {
  document.getElementById("aet-merge-modal")!.style.display = "none";
}

async function submitMerge(e: Event) {
  e.preventDefault();
  const winnerInput = document.querySelector<HTMLInputElement>('input[name="aet-merge-winner"]:checked');
  if (!winnerInput) return;
  const winnerID = winnerInput.value;
  const losers = Array.from(selected).filter((id) => id !== winnerID);
  if (losers.length === 0) return;

  const winner = firmwide.find((r) => r.id === winnerID);
  const totalUsage = firmwide
    .filter((r) => losers.includes(r.id))
    .reduce((acc, r) => acc + r.usage_count, 0);
  const tmpl = t("admin.event_types.confirm.merge")
    || "„{winner}\" als Gewinner: {n} Verlierer-Typ(en) werden archiviert, {usage} Junction-Eintrag/-träge umgeleitet. Fortfahren?";
  const confirmMsg = tmpl
    .replace("{winner}", winner?.label_de ?? winnerID)
    .replace("{n}", String(losers.length))
    .replace("{usage}", String(totalUsage));
  if (!window.confirm(confirmMsg)) return;

  const resp = await fetch("/api/admin/event-types/merge", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ winner_id: winnerID, loser_ids: losers }),
  });
  if (!resp.ok) {
    const body = await resp.json().catch(() => ({ error: resp.statusText }));
    const msgEl = document.getElementById("aet-merge-msg")!;
    msgEl.textContent = body.error || t("admin.event_types.feedback.merge_error") || "Zusammenführung fehlgeschlagen.";
    msgEl.className = "form-msg form-msg-error";
    return;
  }
  closeMergeModal();
  selected.clear();
  showFeedback(t("admin.event_types.feedback.merged") || "Zusammengeführt.", false);
  await Promise.all([loadFirmwide(), loadPrivate()]);
  renderFirmwide();
  renderPrivate();
}

function initSearch() {
  const input = document.getElementById("aet-search") as HTMLInputElement;
  input.addEventListener("input", () => {
    searchQuery = input.value;
    renderFirmwide();
    renderPrivate();
  });
}

function initShowArchivedToggle() {
  const cb = document.getElementById("aet-show-archived") as HTMLInputElement;
  cb.addEventListener("change", async () => {
    showArchived = cb.checked;
    await loadFirmwide();
    renderFirmwide();
  });
}

function initBulkActions() {
  document.getElementById("aet-bulk-archive")!.addEventListener("click", bulkArchiveSelected);
  document.getElementById("aet-bulk-merge")!.addEventListener("click", openMergeModal);
}

function initMergeModal() {
  document.getElementById("aet-merge-close")!.addEventListener("click", closeMergeModal);
  document.getElementById("aet-merge-cancel")!.addEventListener("click", closeMergeModal);
  document.getElementById("aet-merge-modal")!.addEventListener("click", (e) => {
    if (e.target === e.currentTarget) closeMergeModal();
  });
  (document.getElementById("aet-merge-form") as HTMLFormElement).addEventListener("submit", submitMerge);
}

document.addEventListener("DOMContentLoaded", () => {
  initI18n();
  initSidebar();
  initSearch();
  initShowArchivedToggle();
  initBulkActions();
  initMergeModal();
  onLangChange(() => {
    renderFirmwide();
    renderPrivate();
  });
  Promise.all([loadFirmwide(), loadPrivate()]).then(() => {
    renderFirmwide();
    renderPrivate();
  });
});
