"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import { AlertTriangle, Archive, Download, RefreshCcw, RotateCcw, ShieldAlert, Trash2 } from "lucide-react";

import ConfirmDialog from "@/components/common/ConfirmDialog";
import SummaryCard from "@/components/common/SummaryCard";
import { useToast } from "@/components/common/ToastProvider";
import { Button, buttonVariants } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { api } from "@/lib/api";
import { hasPermission } from "@/lib/permissions";
import type { ApiSuccess } from "@/types/audit";
import type { BackupListResponse, BackupSummary, BackupValidationResponse } from "@/types/backup";
import type { CurrentUser } from "@/types/rbac";

const RESTORE_CONFIRM_TEXT = "ICH VERSTEHE DAS RISIKO";

function getErrorMessage(error: unknown, fallback: string) {
  if (typeof error === "object" && error !== null && "response" in error) {
    const response = (error as { response?: { data?: { detail?: string; message?: string } } }).response;
    return response?.data?.detail ?? response?.data?.message ?? fallback;
  }
  return fallback;
}

function formatBytes(bytes: number) {
  if (bytes < 1024) {
    return `${bytes} B`;
  }
  const units = ["KB", "MB", "GB", "TB"];
  let value = bytes / 1024;
  let unitIndex = 0;
  while (value >= 1024 && unitIndex < units.length - 1) {
    value /= 1024;
    unitIndex += 1;
  }
  return `${value.toFixed(value >= 10 ? 0 : 1)} ${units[unitIndex]}`;
}

function formatDate(value: string | null) {
  if (!value) {
    return "Unbekannt";
  }
  return new Intl.DateTimeFormat("de-DE", {
    dateStyle: "medium",
    timeStyle: "short",
  }).format(new Date(value));
}

export default function BackupsPage() {
  const { showToast } = useToast();
  const [data, setData] = useState<BackupListResponse | null>(null);
  const [loading, setLoading] = useState(true);
  const [creating, setCreating] = useState(false);
  const [error, setError] = useState("");
  const [deleteTarget, setDeleteTarget] = useState<BackupSummary | null>(null);
  const [deleting, setDeleting] = useState(false);
  const [validationByFile, setValidationByFile] = useState<Record<string, BackupValidationResponse>>({});
  const [validatingFile, setValidatingFile] = useState("");
  const [restoreTarget, setRestoreTarget] = useState<BackupSummary | null>(null);
  const [restoreConfirm, setRestoreConfirm] = useState("");
  const [restoring, setRestoring] = useState(false);
  const [currentUser, setCurrentUser] = useState<CurrentUser | null>(null);

  const loadBackups = useCallback(async () => {
    setError("");
    try {
      const response = await api.get<ApiSuccess<BackupListResponse>>("/backups");
      setData(response.data.data);
    } catch (err) {
      setError(getErrorMessage(err, "Backups konnten nicht geladen werden."));
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    queueMicrotask(() => {
      void loadBackups();
    });
  }, [loadBackups]);

  useEffect(() => {
    queueMicrotask(async () => {
      try {
        const response = await api.get<CurrentUser>("/me");
        setCurrentUser(response.data);
      } catch {
        setCurrentUser(null);
      }
    });
  }, []);

  const cards = useMemo(() => {
    if (!data) {
      return [];
    }
    return [
      { label: "Backups", value: data.total_count },
      { label: "Gesamtgroesse", value: formatBytes(data.total_size_bytes) },
      { label: "Letztes Backup", value: data.latest_backup_at ? formatDate(data.latest_backup_at) : "Noch keines" },
    ];
  }, [data]);

  const canCreate = hasPermission(currentUser, "backup.create");
  const canDownload = hasPermission(currentUser, "backup.download");
  const canDelete = hasPermission(currentUser, "backup.delete");
  const canRestore = hasPermission(currentUser, "backup.restore");

  async function createBackup() {
    setCreating(true);
    try {
      await api.post<ApiSuccess<BackupSummary>>("/backups/create");
      await loadBackups();
      showToast({ type: "success", title: "Backup erstellt" });
    } catch (err) {
      showToast({
        type: "error",
        title: "Backup konnte nicht erstellt werden",
        description: getErrorMessage(err, "Bitte pruefe die Hermes- und Datenbank-Konfiguration."),
      });
    } finally {
      setCreating(false);
    }
  }

  async function validateBackup(filename: string) {
    setValidatingFile(filename);
    try {
      const response = await api.post<ApiSuccess<BackupValidationResponse>>(`/backups/${encodeURIComponent(filename)}/validate`);
      setValidationByFile((current) => ({ ...current, [filename]: response.data.data }));
      showToast({
        type: response.data.data.valid ? "success" : "error",
        title: response.data.data.valid ? "Backup ist gueltig" : "Backup-Pruefung fehlgeschlagen",
        description: response.data.data.valid ? response.data.data.message : response.data.data.issues.join(" | "),
      });
    } catch (err) {
      showToast({
        type: "error",
        title: "Backup konnte nicht validiert werden",
        description: getErrorMessage(err, "Bitte pruefe die Backup-Datei."),
      });
    } finally {
      setValidatingFile("");
    }
  }

  async function deleteBackup() {
    if (!deleteTarget) {
      return;
    }
    setDeleting(true);
    try {
      await api.delete(`/backups/${encodeURIComponent(deleteTarget.filename)}/delete`);
      setDeleteTarget(null);
      await loadBackups();
      showToast({ type: "success", title: "Backup geloescht" });
    } catch (err) {
      showToast({
        type: "error",
        title: "Backup konnte nicht geloescht werden",
        description: getErrorMessage(err, "Bitte versuche es erneut."),
      });
    } finally {
      setDeleting(false);
    }
  }

  async function restoreBackup() {
    if (!restoreTarget) {
      return;
    }
    setRestoring(true);
    try {
      await api.post(`/backups/${encodeURIComponent(restoreTarget.filename)}/restore`, {
        confirm_text: restoreConfirm,
      });
      showToast({ type: "success", title: "Restore abgeschlossen" });
    } catch (err) {
      showToast({
        type: "info",
        title: "CLI-Restore erforderlich",
        description: getErrorMessage(err, "Automatischer Restore ist derzeit deaktiviert."),
      });
    } finally {
      setRestoring(false);
    }
  }

  if (loading) {
    return <div className="rounded-lg border bg-white p-8 text-slate-500">Backups werden geladen...</div>;
  }

  if (error || !data) {
    return <div className="rounded-lg border bg-white p-8 text-red-600">{error || "Keine Backups verfuegbar"}</div>;
  }

  return (
    <div className="space-y-6">
      <div className="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
        <div>
          <h1 className="text-3xl font-bold text-slate-950">Backups</h1>
          <p className="mt-1 text-sm text-slate-500">PostgreSQL-Dumps, Storage-Dateien und Restore-Validierung zentral verwalten.</p>
        </div>
        <div className="flex flex-wrap gap-2">
          <Button type="button" variant="outline" onClick={() => void loadBackups()}>
            <RefreshCcw />
            Aktualisieren
          </Button>
          {canCreate && (
            <Button type="button" onClick={() => void createBackup()} disabled={creating}>
              <Archive />
              {creating ? "Backup wird erstellt..." : "Backup erstellen"}
            </Button>
          )}
        </div>
      </div>

      <div className="grid gap-4 md:grid-cols-3">
        {cards.map((card) => (
          <SummaryCard key={card.label} label={card.label} value={card.value} />
        ))}
      </div>

      <section className="rounded-lg border bg-white">
        <div className="border-b px-6 py-4">
          <h2 className="text-lg font-semibold text-slate-950">Verfuegbare Backup-Dateien</h2>
        </div>
        {data.items.length === 0 ? (
          <div className="px-6 py-10 text-sm text-slate-500">Noch keine Backup-Dateien vorhanden.</div>
        ) : (
          <div className="divide-y">
            {data.items.map((backup) => {
              const validation = validationByFile[backup.filename];
              return (
                <div key={backup.filename} className="px-6 py-5">
                  <div className="flex flex-col gap-4 xl:flex-row xl:items-start xl:justify-between">
                    <div className="min-w-0 flex-1">
                      <div className="flex flex-wrap items-center gap-3">
                        <p className="truncate font-semibold text-slate-950">{backup.filename}</p>
                        <span className={`inline-flex rounded-full px-2 py-1 text-xs font-medium ${
                          backup.validation_status === "valid"
                            ? "bg-emerald-50 text-emerald-700 ring-1 ring-emerald-600/20"
                            : "bg-amber-50 text-amber-700 ring-1 ring-amber-600/20"
                        }`}>
                          {backup.validation_status === "valid" ? "Manifest lesbar" : "Pruefung empfohlen"}
                        </span>
                      </div>
                      <div className="mt-3 grid gap-3 text-sm text-slate-600 md:grid-cols-2 xl:grid-cols-4">
                        <div>
                          <p className="text-xs uppercase tracking-wide text-slate-400">Erstellt</p>
                          <p>{formatDate(backup.created_at)}</p>
                        </div>
                        <div>
                          <p className="text-xs uppercase tracking-wide text-slate-400">Groesse</p>
                          <p>{formatBytes(backup.size_bytes)}</p>
                        </div>
                        <div>
                          <p className="text-xs uppercase tracking-wide text-slate-400">Version</p>
                          <p>{backup.app_version || "Unbekannt"}</p>
                        </div>
                        <div>
                          <p className="text-xs uppercase tracking-wide text-slate-400">Ersteller</p>
                          <p>{backup.created_by_username || "System"}</p>
                        </div>
                      </div>
                      <div className="mt-3 grid gap-3 text-sm text-slate-600 md:grid-cols-2 xl:grid-cols-4">
                        <div>
                          <p className="text-xs uppercase tracking-wide text-slate-400">Datenbank</p>
                          <p>{backup.database_name || "Unbekannt"}</p>
                        </div>
                        <div>
                          <p className="text-xs uppercase tracking-wide text-slate-400">Dateien</p>
                          <p>{backup.file_count}</p>
                        </div>
                        <div className="md:col-span-2">
                          <p className="text-xs uppercase tracking-wide text-slate-400">Storage-Pfad</p>
                          <p className="break-all">{backup.storage_base_path || "-"}</p>
                        </div>
                      </div>
                      {validation && (
                        <div className={`mt-4 rounded-lg border p-4 text-sm ${
                          validation.valid
                            ? "border-emerald-200 bg-emerald-50 text-emerald-950"
                            : "border-amber-200 bg-amber-50 text-amber-950"
                        }`}>
                          <div className="flex items-start gap-3">
                            {validation.valid ? <RotateCcw className="mt-0.5 h-4 w-4" /> : <AlertTriangle className="mt-0.5 h-4 w-4" />}
                            <div className="space-y-1">
                              <p className="font-medium">{validation.message}</p>
                              <p>Checksumme: {validation.checksum_valid ? "gueltig" : "ungueltig"}</p>
                              {!validation.valid && validation.issues.length > 0 && (
                                <p>{validation.issues.join(" | ")}</p>
                              )}
                              {validation.requires_cli_restore && (
                                <p>Restore ist vorbereitet, muss aktuell aber ueber das CLI-Script ausgefuehrt werden.</p>
                              )}
                            </div>
                          </div>
                        </div>
                      )}
                    </div>
                    <div className="flex shrink-0 flex-wrap gap-2">
                      {canDownload && (
                        <a
                          href={`/api/backups/${encodeURIComponent(backup.filename)}/download`}
                          className={buttonVariants({ variant: "outline" })}
                        >
                          <Download />
                          Download
                        </a>
                      )}
                      {canRestore && (
                        <>
                          <Button
                            type="button"
                            variant="outline"
                            onClick={() => void validateBackup(backup.filename)}
                            disabled={validatingFile === backup.filename}
                          >
                            <ShieldAlert />
                            {validatingFile === backup.filename ? "Prueft..." : "Validieren"}
                          </Button>
                          <Button
                            type="button"
                            variant="outline"
                            onClick={() => {
                              setRestoreTarget(backup);
                              setRestoreConfirm("");
                            }}
                          >
                            <RotateCcw />
                            Restore vorbereiten
                          </Button>
                        </>
                      )}
                      {canDelete && (
                        <Button type="button" variant="destructive" onClick={() => setDeleteTarget(backup)}>
                          <Trash2 />
                          Loeschen
                        </Button>
                      )}
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
        )}
      </section>

      <ConfirmDialog
        open={deleteTarget !== null}
        title="Backup loeschen"
        description="Die Backup-Datei wird dauerhaft entfernt. Diese Aktion kann nicht rueckgaengig gemacht werden."
        confirmLabel="Backup loeschen"
        pending={deleting}
        pendingLabel="Backup wird geloescht..."
        onOpenChange={(open) => {
          if (!open) {
            setDeleteTarget(null);
          }
        }}
        onConfirm={() => void deleteBackup()}
      >
        {deleteTarget && (
          <div className="space-y-1 text-sm text-slate-700">
            <p className="font-medium">{deleteTarget.filename}</p>
            <p>{formatBytes(deleteTarget.size_bytes)}</p>
          </div>
        )}
      </ConfirmDialog>

      <ConfirmDialog
        open={restoreTarget !== null}
        title="Restore vorbereiten"
        description="Restore ist ein Hochrisiko-Vorgang. Bitte bestaetige den Text exakt, bevor Olympus den CLI-Restore vorbereitet."
        confirmLabel="Restore starten"
        pending={restoring}
        pendingLabel="Restore wird vorbereitet..."
        confirmDisabled={restoreConfirm !== RESTORE_CONFIRM_TEXT}
        onOpenChange={(open) => {
          if (!open) {
            setRestoreTarget(null);
            setRestoreConfirm("");
          }
        }}
        onConfirm={() => void restoreBackup()}
      >
        <div className="space-y-3">
          <div className="rounded-lg border border-amber-200 bg-amber-50 p-3 text-sm text-amber-950">
            <div className="flex gap-2">
              <AlertTriangle className="mt-0.5 h-4 w-4 shrink-0" />
              <p>Automatischer Restore ist aus Sicherheitsgruenden deaktiviert. Die Validierung und Auditierung laufen trotzdem ueber Olympus.</p>
            </div>
          </div>
          <div>
            <p className="mb-2 text-sm font-medium text-slate-700">Bestaetigungstext</p>
            <Input
              value={restoreConfirm}
              onChange={(event) => setRestoreConfirm(event.target.value)}
              placeholder={RESTORE_CONFIRM_TEXT}
            />
          </div>
          {restoreTarget && (
            <p className="text-sm text-slate-600">
              Ziel-Backup: <span className="font-medium text-slate-900">{restoreTarget.filename}</span>
            </p>
          )}
        </div>
      </ConfirmDialog>
    </div>
  );
}
