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

// admin-rules-list.ts — /admin/rules. Drives the rule table (filterable
// by proceeding type, trigger event, lifecycle state, free-text query)
// plus the Orphans tab (Slice 10 backfill staging rows). Row click on
// a rule routes to /admin/rules/{id}/edit; orphan cards have their own
// "Pick" affordance with an inline reason prompt that posts to
// /admin/api/orphans/{id}/resolve.

interface Rule {
  id: string;
  proceeding_type_id?: number | null;
  // submission_code is the proceeding-prefixed identifier of this rule
  // within its proceeding (e.g. `upc.inf.cfi.soc`), distinct from
  // rule_code (the legal citation, e.g. `RoP.013.1`).
  submission_code?: string | null;
  rule_code?: string | null;
  name: string;
  name_en: string;
  priority: string;
  lifecycle_state: string;
  updated_at: string;
  trigger_event_id?: number | null;
  duration_value: number;
  duration_unit: string;
}

interface ProceedingType {
  id: number;
  code: string;
  name_de: string;
  name_en: string;
  category: string;
}

interface TriggerEvent {
  id: number;
  code: string;
  name: string;
  name_de: string;
}

interface OrphanCandidate {
  id: string;
  rule_code?: string | null;
  name: string;
  name_en: string;
}

interface Orphan {
  id: string;
  deadline_id: string;
  title: string;
  project_id?: string | null;
  project_title?: string | null;
  proceeding_code?: string | null;
  reason: string;
  candidate_count: number;
  candidate_ids: string[];
  candidates: OrphanCandidate[];
  created_at: string;
}

let rules: Rule[] = [];
let orphans: Orphan[] = [];
let proceedings: ProceedingType[] = [];
let triggerEvents: TriggerEvent[] = [];

let activeProceeding = "";
let activeTrigger = "";
let activeLifecycle = "";
let activeQuery = "";
let searchDebounce: number | undefined;

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

function fmtDateTime(iso: string): string {
  if (!iso) return "";
  const d = new Date(iso);
  if (Number.isNaN(d.getTime())) return iso;
  const locale = getLang() === "de" ? "de-DE" : "en-GB";
  return d.toLocaleString(locale, {
    year: "numeric",
    month: "2-digit",
    day: "2-digit",
    hour: "2-digit",
    minute: "2-digit",
  });
}

function showFeedback(msg: string, isError: boolean) {
  const el = document.getElementById("rules-feedback") as HTMLElement | null;
  if (!el) return;
  el.textContent = msg;
  el.className = "form-msg " + (isError ? "form-msg-error" : "form-msg-success");
  el.style.display = "block";
  if (!isError) {
    setTimeout(() => { el.style.display = "none"; }, 4000);
  }
}

function lifecycleLabel(state: string): string {
  return tDyn(`admin.rules.lifecycle.${state}`) || state;
}

function lifecycleClass(state: string): string {
  switch (state) {
    case "draft": return "admin-rules-pill admin-rules-pill-draft";
    case "published": return "admin-rules-pill admin-rules-pill-published";
    case "archived": return "admin-rules-pill admin-rules-pill-archived";
    default: return "admin-rules-pill";
  }
}

function priorityLabel(p: string): string {
  return tDyn(`admin.rules.priority.${p}`) || p;
}

function proceedingLabel(id: number | null | undefined): string {
  if (id == null) return "—";
  const pt = proceedings.find((p) => p.id === id);
  if (!pt) return `#${id}`;
  const name = getLang() === "en" ? pt.name_en : pt.name_de;
  return `${pt.code} · ${name}`;
}

function buildFilterURL(): string {
  const qs = new URLSearchParams();
  if (activeProceeding) qs.set("proceeding_type_id", activeProceeding);
  if (activeTrigger) qs.set("trigger_event_id", activeTrigger);
  if (activeLifecycle) qs.set("lifecycle_state", activeLifecycle);
  if (activeQuery) qs.set("q", activeQuery);
  qs.set("limit", "500");
  return "/admin/api/rules?" + qs.toString();
}

async function loadProceedings(): Promise<void> {
  const resp = await fetch("/api/proceeding-types-db?category=fristenrechner");
  if (!resp.ok) return;
  proceedings = (await resp.json()) as ProceedingType[];
  const sel = document.getElementById("rules-filter-proceeding") as HTMLSelectElement | null;
  if (!sel) return;
  // Preserve the "Alle" placeholder option then append every proceeding.
  // The placeholder is the one with empty value already in the markup.
  const placeholder = sel.querySelector('option[value=""]');
  sel.innerHTML = "";
  if (placeholder) sel.appendChild(placeholder);
  for (const pt of proceedings) {
    const opt = document.createElement("option");
    opt.value = String(pt.id);
    opt.textContent = `${pt.code} · ${getLang() === "en" ? pt.name_en : pt.name_de}`;
    sel.appendChild(opt);
  }
}

async function loadTriggerEvents(): Promise<void> {
  const resp = await fetch("/api/tools/trigger-events");
  if (!resp.ok) return;
  triggerEvents = (await resp.json()) as TriggerEvent[];
  const sel = document.getElementById("rules-filter-trigger") as HTMLSelectElement | null;
  if (!sel) return;
  const placeholder = sel.querySelector('option[value=""]');
  sel.innerHTML = "";
  if (placeholder) sel.appendChild(placeholder);
  for (const te of triggerEvents) {
    const opt = document.createElement("option");
    opt.value = String(te.id);
    opt.textContent = `${te.code} · ${getLang() === "en" ? te.name : te.name_de}`;
    sel.appendChild(opt);
  }
}

async function loadRules(): Promise<void> {
  const resp = await fetch(buildFilterURL());
  if (!resp.ok) {
    showFeedback(t("admin.rules.error.load") || "Konnte Regeln nicht laden.", true);
    rules = [];
    return;
  }
  const body = await resp.json();
  rules = Array.isArray(body) ? body as Rule[] : [];
}

async function loadOrphans(): Promise<void> {
  const resp = await fetch("/admin/api/orphans");
  if (!resp.ok) {
    orphans = [];
    return;
  }
  const body = await resp.json();
  orphans = Array.isArray(body) ? body as Orphan[] : [];
  updateOrphansBadge();
}

function updateOrphansBadge() {
  const badge = document.getElementById("rules-orphans-badge") as HTMLElement | null;
  if (!badge) return;
  if (orphans.length === 0) {
    badge.style.display = "none";
  } else {
    badge.style.display = "";
    badge.textContent = String(orphans.length);
  }
}

function renderRulesTable() {
  const tbody = document.getElementById("rules-tbody") as HTMLElement | null;
  const empty = document.getElementById("rules-empty") as HTMLElement | null;
  if (!tbody || !empty) return;

  if (rules.length === 0) {
    tbody.innerHTML = "";
    empty.style.display = "block";
    return;
  }
  empty.style.display = "none";
  const name = (r: Rule) => (getLang() === "en" ? r.name_en : r.name) || r.name;
  tbody.innerHTML = rules.map((r) => `
    <tr data-row-id="${esc(r.id)}" class="admin-rules-row">
      <td class="admin-rules-col-code"><code>${esc(r.submission_code || "")}</code></td>
      <td class="admin-rules-col-legal"><code>${esc(r.rule_code || "")}</code></td>
      <td>${esc(name(r))}</td>
      <td>${esc(proceedingLabel(r.proceeding_type_id ?? null))}</td>
      <td><span class="admin-rules-priority admin-rules-priority-${esc(r.priority)}">${esc(priorityLabel(r.priority))}</span></td>
      <td><span class="${lifecycleClass(r.lifecycle_state)}">${esc(lifecycleLabel(r.lifecycle_state))}</span></td>
      <td class="admin-rules-col-modified">${esc(fmtDateTime(r.updated_at))}</td>
    </tr>
  `).join("");

  tbody.querySelectorAll<HTMLElement>(".admin-rules-row").forEach((row) => {
    row.addEventListener("click", (ev) => {
      const target = ev.target as HTMLElement | null;
      if (target && (target.closest("a") || target.closest("button"))) return;
      const id = row.dataset.rowId;
      if (!id) return;
      window.location.href = `/admin/rules/${encodeURIComponent(id)}/edit`;
    });
  });
}

function renderOrphans() {
  const list = document.getElementById("rules-orphans-list") as HTMLElement | null;
  if (!list) return;
  if (orphans.length === 0) {
    list.innerHTML = `<p class="entity-empty" data-i18n="admin.rules.orphans.empty">${esc(t("admin.rules.orphans.empty") || "Keine offenen Orphans. ✔")}</p>`;
    return;
  }
  list.innerHTML = orphans.map((o) => renderOrphanCard(o)).join("");
  list.querySelectorAll<HTMLButtonElement>(".admin-rules-orphan-pick").forEach((btn) => {
    btn.addEventListener("click", () => {
      const orphanId = btn.dataset.orphanId!;
      const ruleId = btn.dataset.ruleId!;
      onPickOrphanCandidate(orphanId, ruleId);
    });
  });
}

function renderOrphanCard(o: Orphan): string {
  const reasonLabel = tDyn(`admin.rules.orphans.reason.${o.reason}`) || o.reason;
  const meta = [
    o.project_title ? `<span class="admin-rules-orphan-meta">${esc(t("admin.rules.orphans.field.project") || "Projekt")}: ${esc(o.project_title)}</span>` : "",
    o.proceeding_code ? `<span class="admin-rules-orphan-meta">${esc(t("admin.rules.orphans.field.proceeding") || "Verfahren")}: <code>${esc(o.proceeding_code)}</code></span>` : "",
    `<span class="admin-rules-orphan-meta">${esc(t("admin.rules.orphans.field.reason") || "Grund")}: ${esc(reasonLabel)}</span>`,
  ].filter(Boolean).join(" · ");

  let candidatesHTML = "";
  if (o.candidates.length === 0) {
    candidatesHTML = `<p class="admin-rules-orphan-empty">${esc(t("admin.rules.orphans.no_candidates") || "Keine Kandidaten gefunden. Bitte Regel manuell anlegen.")}</p>`;
  } else {
    candidatesHTML = `<div class="admin-rules-orphan-candidates">
      ${o.candidates.map((c) => {
        const cname = getLang() === "en" ? c.name_en : c.name;
        return `<button type="button" class="admin-rules-orphan-pick"
          data-orphan-id="${esc(o.id)}" data-rule-id="${esc(c.id)}">
          <code>${esc(c.rule_code || "")}</code>
          <span class="admin-rules-orphan-pick-name">${esc(cname)}</span>
        </button>`;
      }).join("")}
    </div>`;
  }

  return `
    <div class="admin-rules-orphan-card" data-orphan-id="${esc(o.id)}">
      <div class="admin-rules-orphan-header">
        <div class="admin-rules-orphan-title">${esc(o.title)}</div>
        <div class="admin-rules-orphan-metas">${meta}</div>
      </div>
      ${candidatesHTML}
    </div>
  `;
}

// --------------------------------------------------------------------
// Reason modal — shared between "+ Neue Regel" and orphan resolve.
// --------------------------------------------------------------------
type ModalContext =
  | { kind: "new-rule" }
  | { kind: "orphan-resolve"; orphanId: string; ruleId: string };

let modalCtx: ModalContext | null = null;

function openReasonModal(ctx: ModalContext) {
  modalCtx = ctx;
  const modal = document.getElementById("rules-reason-modal") as HTMLElement;
  const title = document.getElementById("rules-reason-title") as HTMLElement;
  const body = document.getElementById("rules-reason-body") as HTMLElement;
  const extra = document.getElementById("rules-reason-extra") as HTMLElement;
  const msg = document.getElementById("rules-reason-msg") as HTMLElement;
  const reasonInput = document.getElementById("rules-reason-text") as HTMLTextAreaElement;
  msg.style.display = "none";
  reasonInput.value = "";
  extra.innerHTML = "";

  if (ctx.kind === "new-rule") {
    title.textContent = t("admin.rules.modal.new.title") || "Neue Regel anlegen";
    body.textContent = t("admin.rules.modal.new.body") || "Eine neue Regel wird als Draft angelegt. Bitte einen Grund angeben.";
    extra.innerHTML = `
      <div class="form-field">
        <label for="rules-new-name" data-i18n="admin.rules.modal.field.name">Name (DE)</label>
        <input type="text" id="rules-new-name" class="admin-rules-input" required minlength="2" />
      </div>
      <div class="form-field">
        <label for="rules-new-name-en" data-i18n="admin.rules.modal.field.name_en">Name (EN)</label>
        <input type="text" id="rules-new-name-en" class="admin-rules-input" required minlength="2" />
      </div>
      <div class="form-field">
        <label for="rules-new-duration" data-i18n="admin.rules.modal.field.duration">Dauer</label>
        <div class="admin-rules-duration-row">
          <input type="number" id="rules-new-duration" class="admin-rules-input" min="0" value="0" required />
          <select id="rules-new-unit" class="admin-rules-select">
            <option value="days">days</option>
            <option value="weeks">weeks</option>
            <option value="months">months</option>
            <option value="working_days">working_days</option>
          </select>
        </div>
      </div>
    `;
  } else {
    title.textContent = t("admin.rules.modal.resolve.title") || "Orphan zuordnen";
    body.textContent = t("admin.rules.modal.resolve.body") || "Bitte einen Grund (mind. 10 Zeichen) angeben.";
  }
  modal.style.display = "flex";
  reasonInput.focus();
}

function closeReasonModal() {
  const modal = document.getElementById("rules-reason-modal") as HTMLElement;
  modal.style.display = "none";
  modalCtx = null;
}

async function submitReasonModal(ev: Event) {
  ev.preventDefault();
  if (!modalCtx) return;
  const reasonInput = document.getElementById("rules-reason-text") as HTMLTextAreaElement;
  const msg = document.getElementById("rules-reason-msg") as HTMLElement;
  const submit = document.getElementById("rules-reason-submit") as HTMLButtonElement;
  const reason = reasonInput.value.trim();
  if (reason.length < 10) {
    msg.textContent = t("admin.rules.modal.reason.too_short") || "Grund muss mindestens 10 Zeichen enthalten.";
    msg.className = "form-msg form-msg-error";
    msg.style.display = "block";
    return;
  }
  submit.disabled = true;
  try {
    if (modalCtx.kind === "new-rule") {
      const name = (document.getElementById("rules-new-name") as HTMLInputElement).value.trim();
      const nameEn = (document.getElementById("rules-new-name-en") as HTMLInputElement).value.trim();
      const duration = parseInt((document.getElementById("rules-new-duration") as HTMLInputElement).value, 10);
      const unit = (document.getElementById("rules-new-unit") as HTMLSelectElement).value;
      if (!name || !nameEn) {
        msg.textContent = t("admin.rules.modal.error.name_required") || "Bitte Name und Name (EN) angeben.";
        msg.className = "form-msg form-msg-error";
        msg.style.display = "block";
        submit.disabled = false;
        return;
      }
      const resp = await fetch("/admin/api/rules", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          name,
          name_en: nameEn,
          duration_value: Number.isFinite(duration) ? duration : 0,
          duration_unit: unit,
          priority: "mandatory",
          is_court_set: false,
          is_spawn: false,
          sequence_order: 0,
          reason,
        }),
      });
      if (!resp.ok) {
        const body = await resp.json().catch(() => ({ error: resp.statusText }));
        msg.textContent = body.error || t("admin.rules.modal.error.create") || "Anlegen fehlgeschlagen.";
        msg.className = "form-msg form-msg-error";
        msg.style.display = "block";
        submit.disabled = false;
        return;
      }
      const created = await resp.json();
      window.location.href = `/admin/rules/${encodeURIComponent(created.id)}/edit`;
      return;
    }

    if (modalCtx.kind === "orphan-resolve") {
      const resp = await fetch(`/admin/api/orphans/${encodeURIComponent(modalCtx.orphanId)}/resolve`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ rule_id: modalCtx.ruleId, reason }),
      });
      if (!resp.ok) {
        const body = await resp.json().catch(() => ({ error: resp.statusText }));
        msg.textContent = body.error || t("admin.rules.modal.error.resolve") || "Zuordnung fehlgeschlagen.";
        msg.className = "form-msg form-msg-error";
        msg.style.display = "block";
        submit.disabled = false;
        return;
      }
      closeReasonModal();
      showFeedback(t("admin.rules.orphans.resolved") || "Orphan zugeordnet.", false);
      await loadOrphans();
      renderOrphans();
    }
  } finally {
    submit.disabled = false;
  }
}

function onPickOrphanCandidate(orphanId: string, ruleId: string) {
  openReasonModal({ kind: "orphan-resolve", orphanId, ruleId });
}

// --------------------------------------------------------------------
// Tabs + filter wiring.
// --------------------------------------------------------------------
function setActiveTab(name: "rules" | "orphans") {
  const paneRules = document.getElementById("rules-pane-rules") as HTMLElement;
  const paneOrphans = document.getElementById("rules-pane-orphans") as HTMLElement;
  const tabRules = document.getElementById("rules-tab-rules") as HTMLElement;
  const tabOrphans = document.getElementById("rules-tab-orphans") as HTMLElement;
  if (name === "rules") {
    paneRules.style.display = "";
    paneOrphans.style.display = "none";
    tabRules.classList.add("active");
    tabOrphans.classList.remove("active");
  } else {
    paneRules.style.display = "none";
    paneOrphans.style.display = "";
    tabRules.classList.remove("active");
    tabOrphans.classList.add("active");
    renderOrphans();
  }
}

function wireFilters() {
  const proc = document.getElementById("rules-filter-proceeding") as HTMLSelectElement;
  const trig = document.getElementById("rules-filter-trigger") as HTMLSelectElement;
  const search = document.getElementById("rules-filter-search") as HTMLInputElement;
  proc.addEventListener("change", async () => {
    activeProceeding = proc.value;
    await loadRules();
    renderRulesTable();
  });
  trig.addEventListener("change", async () => {
    activeTrigger = trig.value;
    await loadRules();
    renderRulesTable();
  });
  search.addEventListener("input", () => {
    window.clearTimeout(searchDebounce);
    searchDebounce = window.setTimeout(async () => {
      activeQuery = search.value.trim();
      await loadRules();
      renderRulesTable();
    }, 220);
  });
  document.querySelectorAll<HTMLButtonElement>("#rules-filter-lifecycle .admin-rules-chip").forEach((chip) => {
    chip.addEventListener("click", async () => {
      document.querySelectorAll(".admin-rules-chip").forEach((c) => c.classList.remove("active"));
      chip.classList.add("active");
      activeLifecycle = chip.dataset.state || "";
      await loadRules();
      renderRulesTable();
    });
  });
}

function wireTabs() {
  (document.getElementById("rules-tab-rules") as HTMLElement).addEventListener("click", () => setActiveTab("rules"));
  (document.getElementById("rules-tab-orphans") as HTMLElement).addEventListener("click", () => setActiveTab("orphans"));
}

function wireModal() {
  (document.getElementById("rules-new-btn") as HTMLElement).addEventListener("click", () => openReasonModal({ kind: "new-rule" }));
  (document.getElementById("rules-reason-cancel") as HTMLElement).addEventListener("click", closeReasonModal);
  (document.getElementById("rules-reason-close") as HTMLElement).addEventListener("click", closeReasonModal);
  (document.getElementById("rules-reason-form") as HTMLFormElement).addEventListener("submit", submitReasonModal);
}

async function init() {
  initI18n();
  initSidebar();
  wireFilters();
  wireTabs();
  wireModal();
  await Promise.all([loadProceedings(), loadTriggerEvents()]);
  await Promise.all([loadRules(), loadOrphans()]);
  renderRulesTable();
  // Re-render proceeding labels when language changes
  onLangChange(() => {
    renderRulesTable();
    renderOrphans();
  });
}

document.addEventListener("DOMContentLoaded", init);
