// Submissions panel — fetches the project's submission catalog and
// renders one row per filing-type rule, with a [Generieren] action
// when a .docx template resolves server-side.
//
// t-paliad-215 Slice 1. Loaded lazily by the projects-detail tab
// switcher so projects without the Schriftsätze tab open don't pay
// for the per-row template-availability probes.

function escapeHtml(s: string): string {
  return s
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#39;");
}

interface SubmissionEntry {
  submission_code: string;
  name: string;
  name_en: string;
  event_type?: string;
  primary_party?: string;
  legal_source?: string;
  has_template: boolean;
}

interface SubmissionListResponse {
  project_id: string;
  proceeding_type_id?: number;
  entries: SubmissionEntry[];
}

// Module state — set once per page load when the user first opens the
// tab. Subsequent activations re-use the cached result so the lawyer
// doesn't pay for repeat list calls flipping between tabs.
let cached: { projectID: string; data: SubmissionListResponse } | null = null;
let loading = false;

/**
 * Load + render the submissions panel for the given project.
 *
 * Idempotent: safe to call on every tab activation. The second call
 * paints from cache instantly; the first call shows a loading state
 * until the list response arrives.
 */
export async function loadAndRenderSubmissions(projectID: string): Promise<void> {
  if (loading) return;
  if (cached && cached.projectID === projectID) {
    render(cached.data);
    return;
  }
  loading = true;
  try {
    const resp = await fetch(`/api/projects/${projectID}/submissions`);
    if (!resp.ok) {
      renderError();
      return;
    }
    const data = (await resp.json()) as SubmissionListResponse;
    cached = { projectID, data };
    render(data);
  } catch {
    renderError();
  } finally {
    loading = false;
  }
}

function render(data: SubmissionListResponse): void {
  const empty = document.getElementById("project-submissions-empty");
  const noProc = document.getElementById("project-submissions-no-proceeding");
  const wrap = document.getElementById("project-submissions-tablewrap");
  const body = document.getElementById("project-submissions-body");
  if (!empty || !noProc || !wrap || !body) return;

  if (data.proceeding_type_id == null || data.proceeding_type_id === 0) {
    noProc.style.display = "";
    empty.style.display = "none";
    wrap.style.display = "none";
    return;
  }
  noProc.style.display = "none";
  if (data.entries.length === 0) {
    empty.style.display = "";
    wrap.style.display = "none";
    return;
  }
  empty.style.display = "none";
  wrap.style.display = "";

  const isEN = document.documentElement.lang === "en";
  body.innerHTML = data.entries.map((entry) => {
    const name = isEN && entry.name_en ? entry.name_en : entry.name;
    const party = formatParty(entry.primary_party, isEN);
    const source = entry.legal_source ?? "";
    const action = entry.has_template
      ? `<button type="button" class="btn-primary btn-cta-lime btn-small submission-generate-btn"
                  data-code="${escapeHtml(entry.submission_code)}"
                  data-project="${escapeHtml(data.project_id)}"
                  data-i18n="projects.detail.submissions.action.generate">${isEN ? "Generate" : "Generieren"}</button>`
      : `<span class="submission-no-template" data-i18n="projects.detail.submissions.action.no_template">${isEN ? "No template" : "Keine Vorlage"}</span>`;
    return `<tr class="submission-row">
      <td>
        <span class="submission-name">${escapeHtml(name)}</span>
        <span class="submission-code">${escapeHtml(entry.submission_code)}</span>
      </td>
      <td>${escapeHtml(party)}</td>
      <td>${escapeHtml(source)}</td>
      <td class="submission-action-cell">${action}</td>
    </tr>`;
  }).join("");

  // Wire button clicks. One click handler per render to avoid stale
  // closures from the previous render's data.
  body.querySelectorAll<HTMLButtonElement>(".submission-generate-btn").forEach((btn) => {
    btn.addEventListener("click", (e) => {
      e.preventDefault();
      e.stopPropagation();
      void onGenerateClick(btn);
    });
  });
}

function renderError(): void {
  const empty = document.getElementById("project-submissions-empty");
  const noProc = document.getElementById("project-submissions-no-proceeding");
  const wrap = document.getElementById("project-submissions-tablewrap");
  if (!empty || !noProc || !wrap) return;
  noProc.style.display = "none";
  wrap.style.display = "none";
  empty.style.display = "";
  empty.textContent = document.documentElement.lang === "en"
    ? "Failed to load submissions list."
    : "Schriftsatzliste konnte nicht geladen werden.";
}

function formatParty(role: string | undefined, isEN: boolean): string {
  switch ((role ?? "").toLowerCase()) {
    case "claimant": return isEN ? "Claimant" : "Klägerin";
    case "defendant": return isEN ? "Defendant" : "Beklagte";
    case "both": return isEN ? "Both" : "Beide";
    case "court": return isEN ? "Court" : "Gericht";
    default: return "";
  }
}

// onGenerateClick triggers a download. Disables the button while the
// request is in flight to prevent double-submits and surfaces an
// inline error on failure.
async function onGenerateClick(btn: HTMLButtonElement): Promise<void> {
  const code = btn.dataset.code;
  const projectID = btn.dataset.project;
  if (!code || !projectID) return;

  const originalLabel = btn.textContent ?? "";
  btn.disabled = true;
  btn.textContent = document.documentElement.lang === "en" ? "Generating…" : "Wird generiert…";

  try {
    const url = `/api/projects/${projectID}/submissions/${encodeURIComponent(code)}/generate`;
    const resp = await fetch(url, { method: "GET" });
    if (!resp.ok) {
      let detail = "";
      try {
        const data = await resp.json() as { error?: string };
        detail = data.error ?? "";
      } catch {
        // fallthrough
      }
      alert(
        (document.documentElement.lang === "en"
          ? "Generation failed."
          : "Generieren fehlgeschlagen.") + (detail ? `\n\n${detail}` : ""),
      );
      return;
    }
    const blob = await resp.blob();
    const filename = parseFilename(resp.headers.get("Content-Disposition") ?? "")
      ?? `${code}.docx`;
    triggerDownload(blob, filename);
  } finally {
    btn.disabled = false;
    btn.textContent = originalLabel;
  }
}

// parseFilename pulls the filename out of a Content-Disposition
// header. Supports both unquoted and quoted forms.
function parseFilename(header: string): string | null {
  const m = /filename\s*=\s*"?([^";]+)"?/i.exec(header);
  return m ? m[1] : null;
}

// triggerDownload creates an <a> with an object URL, clicks it, and
// revokes the URL. Standard browser-side download pattern.
function triggerDownload(blob: Blob, filename: string): void {
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  // Revoke on next tick so the click actually triggers the download
  // before the URL is gone.
  setTimeout(() => URL.revokeObjectURL(url), 0);
}
