"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import { useRouter } from "next/navigation";
import { Icon } from "@/components/ui/Icon";
import { confirmDialog, alertDialog } from "@/components/ui/Dialog";
import { deleteVaultEntryAction, revealSecretAction } from "@/lib/vault/actions";
import type { VaultEntryDTO, ShareTargets } from "@/lib/vault/queries";
import { ViewSwitch } from "@/components/ui/ViewSwitch";
import { categoryColor, useViewMode } from "@/lib/ui/viewMode";
import { VaultDrawer } from "./VaultDrawer";
import { PinDialog } from "./PinDialog";

const REVEAL_SECONDS = 30;
const UNSORTED = "Ohne Kategorie";

type Mode = "reveal" | "copy";
type Revealed = { id: string; value: string };
type PinRequest = { entry: VaultEntryDTO; mode: Mode };

function ageLabel(iso: string): string {
  const days = Math.floor((Date.now() - new Date(iso).getTime()) / 86400000);
  if (days < 1) return "heute geändert";
  if (days === 1) return "gestern geändert";
  if (days < 60) return `vor ${days} Tagen`;
  return `vor ${Math.floor(days / 30)} Monaten`;
}

export function VaultManager({
  userId,
  entries,
  targets,
  canManage,
  canShare,
}: {
  userId: string;
  entries: VaultEntryDTO[];
  targets: ShareTargets;
  canManage: boolean;
  canShare: boolean;
}) {
  const router = useRouter();
  const [query, setQuery] = useState("");
  const [view, setView] = useViewMode(userId, "vault");
  const [category, setCategory] = useState<string | null>(null);
  const [editing, setEditing] = useState<VaultEntryDTO | "new" | null>(null);

  const [revealed, setRevealed] = useState<Revealed | null>(null);
  const [secondsLeft, setSecondsLeft] = useState(0);
  const [pinRequest, setPinRequest] = useState<PinRequest | null>(null);
  const [pinBusy, setPinBusy] = useState(false);
  const [pinError, setPinError] = useState<string | null>(null);
  // Zählt Fehlversuche — setzt die PIN-Maske per key zurück.
  const [pinAttempt, setPinAttempt] = useState(0);
  const [toast, setToast] = useState<{ id: number; text: string } | null>(null);
  const [busyId, setBusyId] = useState<string | null>(null);
  const toastTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
  const toastSeq = useRef(0);

  const categories = useMemo(
    () =>
      [...new Set(entries.map((e) => e.category).filter((c): c is string => Boolean(c)))].sort(),
    [entries],
  );

  const shown = useMemo(() => {
    const q = query.trim().toLowerCase();
    return entries.filter((e) => {
      if (category && e.category !== category) return false;
      if (!q) return true;
      return [e.title, e.username, e.url, e.category].some((v) =>
        (v ?? "").toLowerCase().includes(q),
      );
    });
  }, [entries, query, category]);

  /** Einträge nach Kategorie bündeln — „Ohne Kategorie“ steht am Ende. */
  const grouped = useMemo(() => {
    const map = new Map<string, VaultEntryDTO[]>();
    for (const e of shown) {
      const key = e.category?.trim() || UNSORTED;
      map.set(key, [...(map.get(key) ?? []), e]);
    }
    return [...map.entries()].sort(([a], [b]) => {
      if (a === UNSORTED) return 1;
      if (b === UNSORTED) return -1;
      return a.localeCompare(b, "de");
    });
  }, [shown]);

  // Sichtbares Passwort läuft automatisch ab.
  useEffect(() => {
    if (!revealed) return;
    const end = Date.now() + REVEAL_SECONDS * 1000;
    const id = setInterval(() => {
      const left = Math.ceil((end - Date.now()) / 1000);
      if (left <= 0) setRevealed(null);
      else setSecondsLeft(left);
    }, 400);
    return () => clearInterval(id);
  }, [revealed]);

  /** Kurzer Hinweis unten mittig. */
  const showToast = (text: string) => {
    const id = ++toastSeq.current;
    setToast({ id, text });
    if (toastTimer.current) clearTimeout(toastTimer.current);
    toastTimer.current = setTimeout(() => {
      setToast((t) => (t?.id === id ? null : t));
    }, 2200);
  };

  const copyText = async (text: string, message: string) => {
    try {
      await navigator.clipboard.writeText(text);
      showToast(message);
    } catch {
      await alertDialog({
        title: "Kopieren nicht möglich",
        message: "Der Browser hat den Zugriff auf die Zwischenablage abgelehnt.",
      });
    }
  };

  /** Ergebnis einer erfolgreichen Entschlüsselung verarbeiten. */
  const applySecret = async (entry: VaultEntryDTO, mode: Mode, value: string) => {
    if (mode === "reveal") {
      setSecondsLeft(REVEAL_SECONDS);
      setRevealed({ id: entry.id, value });
      return;
    }
    await copyText(value, "Passwort kopiert");
  };

  /** Passwort kopieren oder anzeigen — fragt bei Bedarf die PIN ab. */
  const requestSecret = async (entry: VaultEntryDTO, mode: Mode) => {
    if (mode === "reveal" && revealed?.id === entry.id) {
      setRevealed(null);
      return;
    }
    if (mode === "copy" && revealed?.id === entry.id) {
      await copyText(revealed.value, "Passwort kopiert");
      return;
    }
    if (entry.pinProtected) {
      setPinError(null);
      setPinRequest({ entry, mode });
      return;
    }

    setBusyId(entry.id);
    const res = await revealSecretAction(entry.id, null);
    setBusyId(null);
    if (!res.ok) {
      await alertDialog({ title: "Nicht möglich", message: res.error, danger: true });
      return;
    }
    await applySecret(entry, mode, res.value);
  };

  const submitPin = async (pin: string) => {
    if (!pinRequest) return;
    setPinBusy(true);
    setPinError(null);
    const res = await revealSecretAction(pinRequest.entry.id, pin);
    setPinBusy(false);

    if (!res.ok) {
      setPinError(res.error);
      setPinAttempt((a) => a + 1);
      return;
    }
    // Richtige PIN → Passwort landet direkt in der Zwischenablage;
    // beim Auge zusätzlich sichtbar machen.
    const { entry, mode } = pinRequest;
    setPinRequest(null);
    await copyText(res.value, "Passwort kopiert");
    if (mode === "reveal") {
      setSecondsLeft(REVEAL_SECONDS);
      setRevealed({ id: entry.id, value: res.value });
    }
  };

  const onDelete = async (e: VaultEntryDTO) => {
    const ok = await confirmDialog({
      title: `„${e.title}“ löschen?`,
      message: "Die Zugangsdaten werden endgültig entfernt — auch für alle Freigegebenen.",
      confirmLabel: "Löschen",
      danger: true,
    });
    if (!ok) return;
    const res = await deleteVaultEntryAction(e.id);
    if (res.error) await alertDialog({ title: "Fehler", message: res.error, danger: true });
    else router.refresh();
  };

  const sharedCount = entries.filter((e) => !e.isOwner).length;
  const pinCount = entries.filter((e) => e.pinProtected).length;

  return (
    <>
      <section className="card" data-reveal>
        {/* Kopfzeile mit Kennzahlen */}
        <div className="mb-4 flex flex-wrap items-center justify-between gap-3">
          <div className="flex flex-wrap items-center gap-2">
            <span className="badge">
              <Icon name="key" size={11} /> {entries.length} Einträge
            </span>
            <span className="badge">
              <Icon name="lock" size={11} /> {pinCount} mit PIN
            </span>
            <span className="badge">
              <Icon name="users" size={11} /> {sharedCount} geteilt
            </span>
          </div>
          <div className="flex flex-wrap items-center gap-2">
            <ViewSwitch value={view} onChange={setView} />
            {canManage ? (
              <button className="btn btn-primary btn-sm" onClick={() => setEditing("new")}>
                <Icon name="plus" size={15} /> Neuer Eintrag
              </button>
            ) : null}
          </div>
        </div>

        {/* Suche & Kategorien */}
        <div className="mb-4 flex flex-wrap items-center gap-2">
          <div className="relative min-w-[220px] flex-1">
            <input
              className="input"
              value={query}
              onChange={(e) => setQuery(e.target.value)}
              placeholder="Suchen nach Titel, Benutzer oder URL …"
              style={{ paddingLeft: 38 }}
            />
            <span className="text-muted pointer-events-none absolute left-3 top-1/2 -translate-y-1/2">
              <Icon name="search" size={16} />
            </span>
          </div>
          {categories.length > 0 ? (
            <div className="flex flex-wrap gap-2">
              <button
                className="pill"
                data-active={category === null}
                onClick={() => setCategory(null)}
              >
                Alle
              </button>
              {categories.map((c) => (
                <button
                  key={c}
                  className="pill"
                  data-active={category === c}
                  onClick={() => setCategory(c === category ? null : c)}
                >
                  {c}
                </button>
              ))}
            </div>
          ) : null}
        </div>

        {shown.length === 0 ? (
          <div className="ui-empty">
            <span className="ui-empty-mark">
              <Icon name={query ? "search" : "key"} size={26} />
            </span>
            <p className="ui-empty-title">
              {entries.length === 0 ? "Noch keine Zugangsdaten" : "Keine Treffer"}
            </p>
            <p className="ui-empty-text">
              {entries.length === 0
                ? "Lege den ersten Eintrag an — Passwörter werden verschlüsselt gespeichert."
                : "Passe die Suche oder den Kategoriefilter an."}
            </p>
            {entries.length === 0 && canManage ? (
              <div className="ui-empty-actions">
                <button className="btn btn-primary btn-sm" onClick={() => setEditing("new")}>
                  <Icon name="plus" size={15} /> Ersten Eintrag anlegen
                </button>
              </div>
            ) : null}
          </div>
        ) : (
          /* Nach Kategorien gegliedert — je Kategorie ein Abschnitt untereinander. */
          <div className="vt-sections">
            {grouped.map(([label, items]) => {
              const color = categoryColor(label === UNSORTED ? null : label);
              return (
                <div key={label}>
                  <div className="vt-group" style={{ ["--cc" as string]: color }}>
                    <span className="vt-group-dot" />
                    {label}
                    <span className="vt-group-count">{items.length}</span>
                  </div>
                  {view === "grid" ? (
                    <div className="vault-grid">
                      {items.map((e) => (
                        <VaultCard
                          key={e.id}
                          entry={e}
                          color={color}
                          revealed={revealed?.id === e.id ? revealed.value : null}
                          secondsLeft={revealed?.id === e.id ? secondsLeft : 0}
                          busy={busyId === e.id}
                          onCopy={() => void requestSecret(e, "copy")}
                          onReveal={() => void requestSecret(e, "reveal")}
                          onCopyText={(text) => void copyText(text, "Benutzername kopiert")}
                          onEdit={() => setEditing(e)}
                          onDelete={() => void onDelete(e)}
                        />
                      ))}
                    </div>
                  ) : (
                    <div className="vt-table">
                      <div className="vt-head">
                        <span>Eintrag</span>
                        <span>Benutzer</span>
                        <span>Passwort</span>
                        <span />
                      </div>
                      {items.map((e) => (
                        <VaultRow
                          key={e.id}
                          entry={e}
                          color={color}
                          revealed={revealed?.id === e.id ? revealed.value : null}
                          secondsLeft={revealed?.id === e.id ? secondsLeft : 0}
                          busy={busyId === e.id}
                          onCopy={() => void requestSecret(e, "copy")}
                          onReveal={() => void requestSecret(e, "reveal")}
                          onCopyText={(text) => void copyText(text, "Benutzername kopiert")}
                          onEdit={() => setEditing(e)}
                          onDelete={() => void onDelete(e)}
                        />
                      ))}
                    </div>
                  )}
                </div>
              );
            })}
          </div>
        )}
      </section>

      {editing ? (
        <VaultDrawer
          entry={editing === "new" ? null : editing}
          targets={targets}
          categories={categories}
          canShare={canShare}
          onClose={() => setEditing(null)}
        />
      ) : null}

      {pinRequest ? (
        <PinDialog
          key={pinAttempt}
          title={pinRequest.entry.title}
          length={pinRequest.entry.pinLength}
          hint={pinRequest.entry.pinHint}
          busy={pinBusy}
          error={pinError}
          onSubmit={(pin) => void submitPin(pin)}
          onClose={() => {
            setPinRequest(null);
            setPinError(null);
          }}
        />
      ) : null}

      {/* Kopier-Hinweis */}
      {toast ? (
        <div className="copy-toast" role="status">
          <span style={{ color: "var(--blue)" }}>
            <Icon name="check" size={15} />
          </span>
          {toast.text}
        </div>
      ) : null}
    </>
  );
}

// ── Einzelner Eintrag ───────────────────────────────────────────────────────

function VaultCard({
  entry,
  color,
  revealed,
  secondsLeft,
  busy,
  onCopy,
  onReveal,
  onCopyText,
  onEdit,
  onDelete,
}: {
  entry: VaultEntryDTO;
  color: string;
  revealed: string | null;
  secondsLeft: number;
  busy: boolean;
  onCopy: () => void;
  onReveal: () => void;
  onCopyText: (text: string) => void;
  onEdit: () => void;
  onDelete: () => void;
}) {
  const shares = entry.users.length + entry.teams.length + entry.roles.length;
  const blocked = busy || entry.locked;

  return (
    <article
      className="vault-card"
      data-locked={entry.locked}
      style={{ ["--cc" as string]: color }}
    >
      {/* Kopf */}
      <div className="flex items-start gap-3">
        <span className="vault-mark" style={{ color }}>
          <Icon name={entry.pinProtected ? "lock" : "key"} size={18} />
        </span>

        <div className="min-w-0 flex-1">
          <div className="flex items-center gap-2">
            <h3 className="truncate" style={{ fontSize: "1rem" }}>
              {entry.title}
            </h3>
            {entry.pinProtected ? <span className="badge">PIN</span> : null}
            {!entry.isOwner ? <span className="badge">geteilt</span> : null}
          </div>
          <div className="text-muted mt-0.5 flex items-center gap-2 text-xs">
            {entry.category ? <span className="truncate">{entry.category}</span> : null}
            {entry.url ? (
              <a
                href={entry.url}
                target="_blank"
                rel="noreferrer noopener"
                className="flex min-w-0 items-center gap-1 truncate hover:text-[color:var(--blue)]"
              >
                <Icon name="globe" size={11} />
                <span className="truncate">{entry.url.replace(/^https?:\/\//, "")}</span>
              </a>
            ) : null}
            {!entry.category && !entry.url ? <span>{ageLabel(entry.rotatedAt)}</span> : null}
          </div>
        </div>
      </div>

      {/* Zwei gleich große Felder — Klick kopiert. */}
      <div className="vault-fields">
        <button
          type="button"
          className="vault-field"
          disabled={!entry.username}
          onClick={() => entry.username && onCopyText(entry.username)}
          title={entry.username ? "Benutzernamen kopieren" : undefined}
        >
          <span className="vault-field-head">
            <span>Benutzer / E-Mail</span>
            {entry.username ? (
              <span className="vault-actions">
                <span className="vault-icon-btn">
                  <Icon name="copy" size={13} />
                </span>
              </span>
            ) : null}
          </span>
          <span className="vault-field-value" data-empty={!entry.username}>
            {entry.username ?? "—"}
          </span>
        </button>

        <button
          type="button"
          className="vault-field"
          data-open={Boolean(revealed)}
          disabled={blocked}
          onClick={onCopy}
          title={entry.locked ? "Gesperrt" : "Passwort kopieren"}
        >
          <span className="vault-field-head">
            <span>Passwort</span>
            {revealed ? <span className="vault-countdown">{secondsLeft}s</span> : null}
            <span className="vault-actions">
              <span
                role="button"
                tabIndex={-1}
                className="vault-icon-btn"
                data-active={Boolean(revealed)}
                onClick={(ev) => {
                  ev.stopPropagation();
                  onReveal();
                }}
                title={revealed ? "Verbergen" : "Anzeigen"}
              >
                <Icon name="eye" size={13} />
              </span>
              <span className="vault-icon-btn">
                <Icon name="copy" size={13} />
              </span>
            </span>
          </span>
          <span className="vault-field-value vault-mono" data-secret={!revealed}>
            {busy ? "…" : entry.locked ? "gesperrt" : (revealed ?? "••••••••••")}
          </span>
        </button>
      </div>

      {entry.notes ? (
        <p className="vault-notes text-muted line-clamp-2 whitespace-pre-wrap text-xs">
          {entry.notes}
        </p>
      ) : null}

      {/* Freigaben */}
      {shares > 0 ? (
        <div className="vault-shares flex flex-wrap items-center gap-1">
          {entry.teams.map((t) => (
            <span key={t.id} className="badge">
              <span className="team-dot" style={{ background: t.color ?? "var(--blue)" }} />
              {t.name}
            </span>
          ))}
          {entry.roles.map((r) => (
            <span key={r.id} className="badge">
              <Icon name="shield" size={11} /> {r.name}
            </span>
          ))}
          {entry.users.slice(0, 3).map((u) => (
            <span key={u.id} className="badge">
              <Icon name="user" size={11} /> {u.name}
            </span>
          ))}
          {entry.users.length > 3 ? (
            <span className="badge">+{entry.users.length - 3}</span>
          ) : null}
        </div>
      ) : null}

      {/* Fußzeile */}
      <div
        className="vault-foot flex items-center justify-between gap-2 border-t pt-2"
        style={{ borderColor: "var(--line)" }}
      >
        <span className="vault-age text-muted text-[11px]">
          {entry.isOwner ? ageLabel(entry.rotatedAt) : `von ${entry.owner.name}`}
        </span>
        <div className="flex items-center gap-1">
          {entry.canEdit ? (
            <button className="btn btn-ghost btn-sm" onClick={onEdit}>
              <Icon name="edit" size={14} /> Bearbeiten
            </button>
          ) : null}
          {entry.canDelete ? (
            <button className="btn btn-ghost btn-sm" onClick={onDelete} title="Löschen">
              <Icon name="trash" size={14} />
            </button>
          ) : null}
        </div>
      </div>
    </article>
  );
}

// ── Listenansicht: eine kompakte Zeile je Eintrag ───────────────────────────

function VaultRow({
  entry,
  color,
  revealed,
  secondsLeft,
  busy,
  onCopy,
  onReveal,
  onCopyText,
  onEdit,
  onDelete,
}: {
  entry: VaultEntryDTO;
  color: string;
  revealed: string | null;
  secondsLeft: number;
  busy: boolean;
  onCopy: () => void;
  onReveal: () => void;
  onCopyText: (text: string) => void;
  onEdit: () => void;
  onDelete: () => void;
}) {
  const blocked = busy || entry.locked;

  return (
    <div className="vt-row" style={{ ["--cc" as string]: color }}>
      {/* Eintrag */}
      <div className="vt-cell vt-cell-title">
        <span className="vt-row-mark">
          <Icon name={entry.pinProtected ? "lock" : "key"} size={15} />
        </span>
        <span className="min-w-0">
          <span className="vt-row-title">
            {entry.title}
            {entry.pinProtected ? <span className="vt-chip">PIN</span> : null}
            {!entry.isOwner ? <span className="vt-chip">geteilt</span> : null}
          </span>
          {entry.url ? (
            <a
              href={entry.url}
              target="_blank"
              rel="noreferrer noopener"
              className="vt-row-sub hover:text-[color:var(--blue)]"
            >
              {entry.url.replace(/^https?:\/\//, "")}
            </a>
          ) : (
            <span className="vt-row-sub">{ageLabel(entry.rotatedAt)}</span>
          )}
        </span>
      </div>

      {/* Benutzer */}
      <button
        type="button"
        className="vt-cell vt-copy"
        disabled={!entry.username}
        onClick={() => entry.username && onCopyText(entry.username)}
        title={entry.username ? "Benutzernamen kopieren" : undefined}
      >
        <span className="truncate">{entry.username ?? "—"}</span>
        {entry.username ? <Icon name="copy" size={13} className="vt-copy-icon" /> : null}
      </button>

      {/* Passwort */}
      <div className="vt-cell vt-secret">
        <button
          type="button"
          className="vt-copy min-w-0 flex-1"
          disabled={blocked}
          onClick={onCopy}
          title={entry.locked ? "Gesperrt" : "Passwort kopieren"}
        >
          <span className="vault-mono truncate">
            {busy ? "…" : entry.locked ? "gesperrt" : (revealed ?? "••••••••")}
          </span>
          {!blocked ? <Icon name="copy" size={13} className="vt-copy-icon" /> : null}
        </button>
        {revealed ? <span className="vt-count">{secondsLeft}s</span> : null}
        <button
          type="button"
          className="vault-icon-btn"
          data-active={Boolean(revealed)}
          onClick={onReveal}
          disabled={blocked}
          title={revealed ? "Verbergen" : "Anzeigen"}
        >
          <Icon name="eye" size={14} />
        </button>
      </div>

      {/* Aktionen */}
      <div className="vt-cell vt-actions">
        {entry.canEdit ? (
          <button className="vault-icon-btn" onClick={onEdit} title="Bearbeiten">
            <Icon name="edit" size={14} />
          </button>
        ) : null}
        {entry.canDelete ? (
          <button className="vault-icon-btn" onClick={onDelete} title="Löschen">
            <Icon name="trash" size={14} />
          </button>
        ) : null}
      </div>
    </div>
  );
}
