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

// Backup Mode admin client (t-paliad-246 / m/paliad#77 Slice A).
//
// Reads /api/admin/backups (chronological list) and wires the
// "Backup jetzt erstellen" button to POST /api/admin/backups/run.
// Synchronous: the server holds the connection for the duration of
// the backup (sub-second at firm-scale today), then returns the new
// catalog row inline. No polling needed at v1's data shape; if the
// run takes > 5 minutes the handler returns 500 and the UI surfaces
// the error.

interface BackupRow {
  id: string;
  kind: "scheduled" | "on_demand";
  status: "running" | "done" | "failed";
  requested_by?: string;
  requested_by_email: string;
  audit_id?: string;
  storage_uri?: string;
  size_bytes?: number;
  row_counts?: unknown; // jsonb passes through as raw bytes; we don't read it
  sheet_count?: number;
  warnings?: unknown;
  error?: string;
  started_at: string;
  finished_at?: string;
  deleted_at?: string;
}

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

  await refreshList();
  wireRunButton();
});

function wireRunButton(): void {
  const btn = document.getElementById("admin-backups-run-btn") as HTMLButtonElement | null;
  if (!btn) return;
  btn.addEventListener("click", async () => {
    btn.disabled = true;
    const originalText = btn.textContent;
    btn.textContent = t("admin.backups.running") || "Läuft …";
    clearFeedback();
    try {
      const r = await fetch("/api/admin/backups/run", {
        method: "POST",
        credentials: "same-origin",
      });
      if (!r.ok) {
        const body = await r.json().catch(() => ({ error: "request failed" }));
        showFeedback("error", body.error || `HTTP ${r.status}`);
        return;
      }
      // The created row is in the response; refresh the list to land it.
      await refreshList();
      showFeedback("success", t("admin.backups.success") || "Backup erfolgreich erstellt.");
    } catch (e) {
      showFeedback("error", (e as Error).message || "network error");
    } finally {
      btn.disabled = false;
      btn.textContent = originalText;
    }
  });
}

async function refreshList(): Promise<void> {
  const rows = await fetchJSON<BackupRow[]>("/api/admin/backups?limit=200");
  const tbody = document.getElementById("admin-backups-tbody") as HTMLTableSectionElement | null;
  const empty = document.getElementById("admin-backups-empty") as HTMLElement | null;
  if (!tbody) return;
  if (!rows || rows.length === 0) {
    tbody.innerHTML = "";
    if (empty) empty.style.display = "";
    return;
  }
  if (empty) empty.style.display = "none";
  tbody.innerHTML = rows.map(renderRow).join("");
}

function renderRow(b: BackupRow): string {
  const started = formatTimestamp(b.started_at);
  const kind =
    b.kind === "scheduled"
      ? t("admin.backups.kind.scheduled") || "Geplant"
      : t("admin.backups.kind.on_demand") || "Manuell";
  const status = renderStatus(b);
  const requestedBy =
    b.kind === "scheduled" ? "—" : escapeHTML(b.requested_by_email);
  const size = b.size_bytes != null ? formatBytes(b.size_bytes) : "—";
  const rows = b.sheet_count != null ? String(b.sheet_count) : "—";
  const action = renderAction(b);
  return `<tr>
    <td>${started}</td>
    <td>${kind}</td>
    <td>${status}</td>
    <td>${requestedBy}</td>
    <td>${size}</td>
    <td>${rows}</td>
    <td>${action}</td>
  </tr>`;
}

function renderStatus(b: BackupRow): string {
  switch (b.status) {
    case "done":
      return `<span class="status-done">${escapeHTML(t("admin.backups.status.done") || "✓ Fertig")}</span>`;
    case "running":
      return `<span class="status-running">${escapeHTML(t("admin.backups.status.running") || "Läuft …")}</span>`;
    case "failed":
      const label = t("admin.backups.status.failed") || "✗ Fehlgeschlagen";
      const tip = b.error ? ` title="${escapeAttr(b.error)}"` : "";
      return `<span class="status-failed"${tip}>${escapeHTML(label)}</span>`;
    default:
      return escapeHTML(b.status);
  }
}

function renderAction(b: BackupRow): string {
  if (b.status !== "done" || !b.storage_uri || b.deleted_at) {
    return "—";
  }
  const label = t("admin.backups.download") || "Download";
  return `<a class="btn-link" href="/api/admin/backups/${encodeURIComponent(b.id)}/file">${escapeHTML(label)}</a>`;
}

// --- helpers ---

async function fetchJSON<T>(url: string): Promise<T | null> {
  try {
    const r = await fetch(url, { credentials: "same-origin" });
    if (!r.ok) return null;
    return (await r.json()) as T;
  } catch {
    return null;
  }
}

function formatTimestamp(iso: string): string {
  const d = new Date(iso);
  if (isNaN(d.getTime())) return escapeHTML(iso);
  const yyyy = d.getUTCFullYear();
  const mm = String(d.getUTCMonth() + 1).padStart(2, "0");
  const dd = String(d.getUTCDate()).padStart(2, "0");
  const hh = String(d.getUTCHours()).padStart(2, "0");
  const mi = String(d.getUTCMinutes()).padStart(2, "0");
  return `${yyyy}-${mm}-${dd} ${hh}:${mi} UTC`;
}

function formatBytes(n: number): string {
  if (n < 1024) return `${n} B`;
  if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
  if (n < 1024 * 1024 * 1024) return `${(n / (1024 * 1024)).toFixed(1)} MB`;
  return `${(n / (1024 * 1024 * 1024)).toFixed(2)} GB`;
}

function escapeHTML(s: string): string {
  return s.replace(/[&<>"']/g, (c) => {
    switch (c) {
      case "&": return "&amp;";
      case "<": return "&lt;";
      case ">": return "&gt;";
      case '"': return "&quot;";
      case "'": return "&#39;";
      default: return c;
    }
  });
}

function escapeAttr(s: string): string {
  return escapeHTML(s);
}

function showFeedback(kind: "success" | "error", text: string): void {
  const el = document.getElementById("admin-backups-feedback") as HTMLElement | null;
  if (!el) return;
  el.textContent = text;
  el.classList.remove("form-msg-success", "form-msg-error");
  el.classList.add(kind === "success" ? "form-msg-success" : "form-msg-error");
  el.style.display = "";
}

function clearFeedback(): void {
  const el = document.getElementById("admin-backups-feedback") as HTMLElement | null;
  if (!el) return;
  el.style.display = "none";
  el.textContent = "";
  el.classList.remove("form-msg-success", "form-msg-error");
}
