import { createFileRoute, Navigate, useNavigate } from "@tanstack/react-router";
import { useEffect, useMemo, useState } from "react";
import { supabase } from "@/integrations/supabase/client";
import { useVault } from "@/lib/vault-context";
import {
  deriveKey,
  encryptString,
  decryptString,
  hashPin,
  randomSaltB64,
} from "@/lib/crypto";
import {
  isBiometricSupported,
  registerBiometric,
  verifyBiometric,
  cachePinForBiometric,
  getCachedPin,
  clearCachedPin,
} from "@/lib/biometric";
import {
  Shield,
  Search,
  Plus,
  LogOut,
  KeyRound,
  CreditCard,
  Copy,
  Eye,
  EyeOff,
  Trash2,
  Pencil,
  Fingerprint,
  Folder,
  Settings as SettingsIcon,
  X,
  ExternalLink,
} from "lucide-react";
import { toast } from "sonner";

export const Route = createFileRoute("/vault")({
  component: VaultGate,
  head: () => ({ meta: [{ title: "Meu cofre — AppPass" }] }),
});

function VaultGate() {
  const { session, loading, profile, vaultKey } = useVault();
  if (loading) return <FullscreenSpinner />;
  if (!session) return <Navigate to="/login" />;
  if (!profile) return <FullscreenSpinner />;
  if (!profile.master_pin_hash || !profile.encryption_salt) return <SetupPin />;
  if (!vaultKey) return <UnlockScreen />;
  return <Dashboard />;
}

function FullscreenSpinner() {
  return (
    <div className="flex min-h-screen items-center justify-center">
      <div className="h-8 w-8 animate-spin rounded-full border-2 border-border border-t-gold" />
    </div>
  );
}

/* ---------------- PIN SETUP ---------------- */

function SetupPin() {
  const { session, refreshProfile, setVaultKey } = useVault();
  const [pin, setPin] = useState("");
  const [confirm, setConfirm] = useState("");
  const [recoveryEmail, setRecoveryEmail] = useState(session?.user?.email ?? "");
  const [busy, setBusy] = useState(false);

  const save = async (e: React.FormEvent) => {
    e.preventDefault();
    if (pin.length < 4) return toast.error("Use ao menos 4 dígitos.");
    if (pin !== confirm) return toast.error("PINs não conferem.");
    setBusy(true);
    try {
      const salt = randomSaltB64();
      const pinHash = await hashPin(pin, salt);
      const key = await deriveKey(pin, salt);
      const { error } = await supabase
        .from("profiles")
        .update({
          master_pin_hash: pinHash,
          encryption_salt: salt,
          recovery_email: recoveryEmail || null,
        })
        .eq("id", session!.user.id);
      if (error) throw error;
      cachePinForBiometric(session!.user.id, pin);
      setVaultKey(key);
      await refreshProfile();
      toast.success("Cofre criado!");
    } catch (err) {
      toast.error((err as Error).message);
    } finally {
      setBusy(false);
    }
  };

  return (
    <main className="flex min-h-screen items-center justify-center px-4">
      <div className="w-full max-w-md rounded-2xl border border-border bg-card p-6 shadow-vault">
        <Shield className="h-8 w-8 text-gold" />
        <h1 className="mt-3 font-display text-3xl">Criar PIN mestre</h1>
        <p className="mt-1 text-sm text-muted-foreground">
          Este PIN cifra seu cofre localmente. Sem ele, ninguém — nem nós — pode ler seus dados.
        </p>
        <form onSubmit={save} className="mt-6 space-y-3">
          <div>
            <label className="text-xs text-muted-foreground">PIN (4+ dígitos)</label>
            <input
              type="password"
              inputMode="numeric"
              autoFocus
              value={pin}
              onChange={(e) => setPin(e.target.value)}
              className="mt-1 w-full rounded-lg border border-border bg-input px-3 py-2.5 text-lg tracking-[0.4em] outline-none focus:border-gold"
            />
          </div>
          <div>
            <label className="text-xs text-muted-foreground">Confirmar PIN</label>
            <input
              type="password"
              inputMode="numeric"
              value={confirm}
              onChange={(e) => setConfirm(e.target.value)}
              className="mt-1 w-full rounded-lg border border-border bg-input px-3 py-2.5 text-lg tracking-[0.4em] outline-none focus:border-gold"
            />
          </div>
          <div>
            <label className="text-xs text-muted-foreground">E-mail de recuperação</label>
            <input
              type="email"
              value={recoveryEmail}
              onChange={(e) => setRecoveryEmail(e.target.value)}
              className="mt-1 w-full rounded-lg border border-border bg-input px-3 py-2.5 text-sm outline-none focus:border-gold"
            />
          </div>
          <button disabled={busy} className="w-full rounded-lg bg-gold-gradient px-4 py-2.5 text-sm font-semibold text-accent-foreground shadow-gold disabled:opacity-50">
            {busy ? "Cifrando..." : "Criar cofre"}
          </button>
        </form>
      </div>
    </main>
  );
}

/* ---------------- UNLOCK ---------------- */

function UnlockScreen() {
  const { session, profile, setVaultKey, signOut } = useVault();
  const [pin, setPin] = useState("");
  const [busy, setBusy] = useState(false);

  const creds = (profile?.webauthn_credentials as Array<{ id: string }> | null) || [];
  const hasBio = creds.length > 0 && isBiometricSupported();

  const unlockWithPin = async (raw?: string) => {
    const value = raw ?? pin;
    if (!profile?.encryption_salt || !profile.master_pin_hash) return;
    setBusy(true);
    try {
      const h = await hashPin(value, profile.encryption_salt);
      if (h !== profile.master_pin_hash) {
        toast.error("PIN incorreto.");
        return;
      }
      const key = await deriveKey(value, profile.encryption_salt);
      cachePinForBiometric(session!.user.id, value);
      setVaultKey(key);
    } finally {
      setBusy(false);
    }
  };

  const unlockWithBio = async () => {
    if (!hasBio) return;
    setBusy(true);
    try {
      const ok = await verifyBiometric(creds[0].id);
      if (!ok) {
        toast.error("Biometria não reconhecida. Use o PIN.");
        return;
      }
      const cachedPin = getCachedPin(session!.user.id);
      if (!cachedPin) {
        toast.error("Sessão biométrica expirada. Use o PIN uma vez.");
        return;
      }
      const key = await deriveKey(cachedPin, profile!.encryption_salt!);
      setVaultKey(key);
    } finally {
      setBusy(false);
    }
  };

  return (
    <main className="flex min-h-screen items-center justify-center px-4">
      <div className="w-full max-w-md rounded-2xl border border-border bg-card p-6 shadow-vault text-center">
        <Shield className="mx-auto h-8 w-8 text-gold" />
        <h1 className="mt-3 font-display text-3xl">Desbloquear cofre</h1>
        <p className="mt-1 text-sm text-muted-foreground">Olá, {profile?.display_name || session?.user?.email}</p>

        {hasBio && (
          <button
            onClick={unlockWithBio}
            disabled={busy}
            className="mx-auto mt-6 flex items-center gap-2 rounded-full bg-emerald-gradient px-6 py-3 text-sm font-medium shadow-vault disabled:opacity-50"
          >
            <Fingerprint className="h-5 w-5 text-gold" /> Desbloquear com biometria
          </button>
        )}

        <form
          onSubmit={(e) => { e.preventDefault(); unlockWithPin(); }}
          className="mt-6 space-y-3"
        >
          <input
            type="password"
            inputMode="numeric"
            autoFocus
            placeholder="Digite seu PIN"
            value={pin}
            onChange={(e) => setPin(e.target.value)}
            className="w-full rounded-lg border border-border bg-input px-3 py-3 text-center text-xl tracking-[0.5em] outline-none focus:border-gold"
          />
          <button disabled={busy} className="w-full rounded-lg bg-gold-gradient px-4 py-2.5 text-sm font-semibold text-accent-foreground shadow-gold disabled:opacity-50">
            {busy ? "Verificando..." : "Desbloquear"}
          </button>
        </form>

        <button onClick={signOut} className="mt-6 text-xs text-muted-foreground hover:text-foreground">
          <LogOut className="mr-1 inline h-3 w-3" /> Sair da conta
        </button>
      </div>
    </main>
  );
}

/* ---------------- DASHBOARD ---------------- */

type Category = { id: string; name: string; color: string };
type VaultItem = {
  id: string;
  category_id: string | null;
  item_type: "password" | "card";
  title: string;
  login_url: string | null;
  username_enc: string | null;
  password_enc: string | null;
  notes_enc: string | null;
  card_number_enc: string | null;
  card_holder_enc: string | null;
  card_expiry_enc: string | null;
  card_cvv_enc: string | null;
  updated_at: string;
};

function Dashboard() {
  const { session, profile, vaultKey, setVaultKey, signOut } = useVault();
  const navigate = useNavigate();
  const [categories, setCategories] = useState<Category[]>([]);
  const [items, setItems] = useState<VaultItem[]>([]);
  const [query, setQuery] = useState("");
  const [activeCat, setActiveCat] = useState<string | "all">("all");
  const [showItem, setShowItem] = useState<VaultItem | null>(null);
  const [editing, setEditing] = useState<VaultItem | null>(null);
  const [creatingType, setCreatingType] = useState<"password" | "card" | null>(null);
  const [showSettings, setShowSettings] = useState(false);
  const [newCatName, setNewCatName] = useState("");

  const load = async () => {
    const [{ data: cats }, { data: vis }] = await Promise.all([
      supabase.from("categories").select("*").order("created_at"),
      supabase.from("vault_items").select("*").order("updated_at", { ascending: false }),
    ]);
    setCategories((cats as Category[]) || []);
    setItems((vis as VaultItem[]) || []);
  };

  useEffect(() => {
    load();
    // seed default categories on first load if empty
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    if (categories.length === 0 && session) {
      (async () => {
        await supabase.from("categories").insert([
          { user_id: session.user.id, name: "Sites", color: "#0d7a5f", icon: "globe" },
          { user_id: session.user.id, name: "Apps", color: "#c9a84c", icon: "smartphone" },
          { user_id: session.user.id, name: "Cartões", color: "#5cbdb9", icon: "credit-card" },
        ]);
        load();
      })();
    }
  }, [categories.length, session]);

  const filtered = useMemo(() => {
    const q = query.toLowerCase().trim();
    return items.filter((i) => {
      if (activeCat !== "all" && i.category_id !== activeCat) return false;
      if (!q) return true;
      return (
        i.title.toLowerCase().includes(q) ||
        (i.login_url ?? "").toLowerCase().includes(q)
      );
    });
  }, [items, query, activeCat]);

  const lock = () => {
    setVaultKey(null);
  };

  const addCategory = async () => {
    const name = newCatName.trim();
    if (!name) return;
    const { error } = await supabase.from("categories").insert({
      user_id: session!.user.id,
      name,
      color: "#0d7a5f",
    });
    if (error) toast.error(error.message);
    setNewCatName("");
    load();
  };

  const deleteCategory = async (id: string) => {
    if (!confirm("Excluir categoria? Itens permanecerão sem categoria.")) return;
    await supabase.from("categories").delete().eq("id", id);
    load();
  };

  const deleteItem = async (id: string) => {
    if (!confirm("Excluir este item?")) return;
    await supabase.from("vault_items").delete().eq("id", id);
    setShowItem(null);
    load();
  };

  return (
    <main className="min-h-screen pb-24">
      <header className="sticky top-0 z-20 border-b border-border bg-background/80 backdrop-blur">
        <div className="mx-auto flex max-w-5xl items-center gap-3 px-4 py-3">
          <div className="flex items-center gap-2 text-gold">
            <Shield className="h-5 w-5" />
            <span className="font-display text-xl">AppPass</span>
          </div>
          <div className="flex-1" />
          <button onClick={() => setShowSettings(true)} className="rounded-lg p-2 hover:bg-secondary" aria-label="Configurações">
            <SettingsIcon className="h-4 w-4" />
          </button>
          <button onClick={lock} className="rounded-lg p-2 hover:bg-secondary" aria-label="Bloquear">
            <KeyRound className="h-4 w-4" />
          </button>
          <button onClick={() => { signOut(); navigate({ to: "/" }); }} className="rounded-lg p-2 hover:bg-secondary" aria-label="Sair">
            <LogOut className="h-4 w-4" />
          </button>
        </div>

        <div className="mx-auto max-w-5xl px-4 pb-3">
          <div className="relative">
            <Search className="pointer-events-none absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
            <input
              placeholder="Buscar por título ou link..."
              value={query}
              onChange={(e) => setQuery(e.target.value)}
              className="w-full rounded-xl border border-border bg-card px-10 py-3 text-sm outline-none focus:border-gold"
            />
          </div>

          <div className="mt-3 flex flex-wrap items-center gap-2">
            <Chip active={activeCat === "all"} onClick={() => setActiveCat("all")}>Todos</Chip>
            {categories.map((c) => (
              <Chip key={c.id} active={activeCat === c.id} onClick={() => setActiveCat(c.id)} color={c.color}>
                {c.name}
              </Chip>
            ))}
          </div>
        </div>
      </header>

      <section className="mx-auto max-w-5xl px-4 pt-5">
        {filtered.length === 0 ? (
          <EmptyState onAdd={() => setCreatingType("password")} />
        ) : (
          <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
            {filtered.map((item) => (
              <ItemCard
                key={item.id}
                item={item}
                category={categories.find((c) => c.id === item.category_id)}
                onOpen={() => setShowItem(item)}
              />
            ))}
          </div>
        )}
      </section>

      {/* Floating add button */}
      <div className="fixed right-4 bottom-4 z-30 flex flex-col items-end gap-2">
        <button
          onClick={() => setCreatingType("card")}
          className="flex items-center gap-2 rounded-full border border-border bg-card px-4 py-2 text-sm shadow-vault hover:bg-secondary"
        >
          <CreditCard className="h-4 w-4 text-gold" /> Cartão
        </button>
        <button
          onClick={() => setCreatingType("password")}
          className="flex items-center gap-2 rounded-full bg-gold-gradient px-5 py-3 text-sm font-semibold text-accent-foreground shadow-gold"
        >
          <Plus className="h-4 w-4" /> Nova senha
        </button>
      </div>

      {showItem && vaultKey && (
        <ItemDetail
          item={showItem}
          category={categories.find((c) => c.id === showItem.category_id)}
          vaultKey={vaultKey}
          onClose={() => setShowItem(null)}
          onEdit={() => { setEditing(showItem); setShowItem(null); }}
          onDelete={() => deleteItem(showItem.id)}
        />
      )}

      {(creatingType || editing) && vaultKey && session && (
        <ItemEditor
          userId={session.user.id}
          categories={categories}
          vaultKey={vaultKey}
          item={editing ?? undefined}
          defaultType={creatingType ?? editing?.item_type ?? "password"}
          onClose={() => { setCreatingType(null); setEditing(null); }}
          onSaved={() => { setCreatingType(null); setEditing(null); load(); }}
        />
      )}

      {showSettings && (
        <SettingsDialog
          onClose={() => setShowSettings(false)}
          categories={categories}
          onAddCategory={addCategory}
          onDeleteCategory={deleteCategory}
          newCatName={newCatName}
          setNewCatName={setNewCatName}
          reload={load}
        />
      )}
    </main>
  );
}

function Chip({ children, active, onClick, color }: { children: React.ReactNode; active?: boolean; onClick?: () => void; color?: string }) {
  return (
    <button
      onClick={onClick}
      className={
        "flex items-center gap-1.5 rounded-full border px-3 py-1 text-xs transition " +
        (active
          ? "border-gold bg-gold-gradient text-accent-foreground"
          : "border-border bg-card hover:bg-secondary")
      }
    >
      {color && <span className="h-2 w-2 rounded-full" style={{ background: color }} />}
      {children}
    </button>
  );
}

function EmptyState({ onAdd }: { onAdd: () => void }) {
  return (
    <div className="rounded-2xl border border-dashed border-border p-10 text-center">
      <Folder className="mx-auto h-10 w-10 text-muted-foreground" />
      <h3 className="mt-3 font-display text-xl">Seu cofre está vazio</h3>
      <p className="mt-1 text-sm text-muted-foreground">Adicione sua primeira senha para começar.</p>
      <button onClick={onAdd} className="mt-4 rounded-lg bg-gold-gradient px-4 py-2 text-sm font-semibold text-accent-foreground shadow-gold">
        <Plus className="mr-1 inline h-4 w-4" /> Nova senha
      </button>
    </div>
  );
}

function ItemCard({ item, category, onOpen }: { item: VaultItem; category?: Category; onOpen: () => void }) {
  const Icon = item.item_type === "card" ? CreditCard : KeyRound;
  return (
    <button onClick={onOpen} className="group rounded-xl border border-border bg-card p-4 text-left shadow-vault transition hover:border-gold">
      <div className="flex items-start justify-between">
        <div className="flex items-center gap-2">
          <div className="rounded-lg bg-secondary p-2">
            <Icon className="h-4 w-4 text-gold" />
          </div>
          <div>
            <div className="font-medium leading-tight">{item.title}</div>
            {item.login_url && (
              <div className="mt-0.5 max-w-[200px] truncate text-xs text-muted-foreground">{item.login_url}</div>
            )}
          </div>
        </div>
        {category && (
          <span className="rounded-full px-2 py-0.5 text-[10px]" style={{ background: category.color + "33", color: category.color }}>
            {category.name}
          </span>
        )}
      </div>
    </button>
  );
}

/* ---------------- ITEM DETAIL ---------------- */

function ItemDetail({
  item, category, vaultKey, onClose, onEdit, onDelete,
}: {
  item: VaultItem;
  category?: Category;
  vaultKey: CryptoKey;
  onClose: () => void;
  onEdit: () => void;
  onDelete: () => void;
}) {
  const [data, setData] = useState<Record<string, string>>({});
  const [reveal, setReveal] = useState<Record<string, boolean>>({});

  useEffect(() => {
    (async () => {
      const out: Record<string, string> = {};
      const fields: Array<[keyof VaultItem, string]> = [
        ["username_enc", "username"],
        ["password_enc", "password"],
        ["notes_enc", "notes"],
        ["card_number_enc", "card_number"],
        ["card_holder_enc", "card_holder"],
        ["card_expiry_enc", "card_expiry"],
        ["card_cvv_enc", "card_cvv"],
      ];
      for (const [src, dst] of fields) {
        const v = item[src] as string | null;
        if (v) out[dst] = await decryptString(vaultKey, v);
      }
      setData(out);
    })();
  }, [item, vaultKey]);

  const copy = async (label: string, value?: string) => {
    if (!value) return;
    await navigator.clipboard.writeText(value);
    toast.success(`${label} copiado`);
  };

  const isCard = item.item_type === "card";

  return (
    <Modal onClose={onClose}>
      <div className="flex items-start justify-between gap-3">
        <div>
          <div className="flex items-center gap-2 text-xs text-muted-foreground">
            {category && <span className="rounded-full px-2 py-0.5" style={{ background: category.color + "33", color: category.color }}>{category.name}</span>}
            <span>{isCard ? "Cartão" : "Senha"}</span>
          </div>
          <h2 className="mt-1 font-display text-3xl">{item.title}</h2>
        </div>
        <div className="flex gap-1">
          <IconBtn onClick={onEdit} title="Editar"><Pencil className="h-4 w-4" /></IconBtn>
          <IconBtn onClick={onDelete} title="Excluir"><Trash2 className="h-4 w-4 text-destructive" /></IconBtn>
        </div>
      </div>

      <div className="mt-6 space-y-3">
        {item.login_url && (
          <Field label="Link de login">
            <a href={item.login_url.startsWith("http") ? item.login_url : `https://${item.login_url}`} target="_blank" rel="noreferrer" className="flex items-center gap-1 truncate text-gold hover:underline">
              {item.login_url} <ExternalLink className="h-3 w-3" />
            </a>
            <ActionBtns onCopy={() => copy("Link", item.login_url!)} />
          </Field>
        )}

        {!isCard && (
          <>
            {data.username && (
              <Field label="Usuário">
                <span className="font-mono text-sm">{data.username}</span>
                <ActionBtns onCopy={() => copy("Usuário", data.username)} />
              </Field>
            )}
            {data.password && (
              <Field label="Senha">
                <span className="font-mono text-sm">{reveal.password ? data.password : "••••••••••"}</span>
                <ActionBtns
                  onToggle={() => setReveal((r) => ({ ...r, password: !r.password }))}
                  shown={reveal.password}
                  onCopy={() => copy("Senha", data.password)}
                />
              </Field>
            )}
          </>
        )}

        {isCard && (
          <>
            {data.card_number && (
              <Field label="Número">
                <span className="font-mono text-sm">{reveal.num ? data.card_number : maskCard(data.card_number)}</span>
                <ActionBtns
                  onToggle={() => setReveal((r) => ({ ...r, num: !r.num }))}
                  shown={reveal.num}
                  onCopy={() => copy("Número", data.card_number)}
                />
              </Field>
            )}
            {data.card_holder && <Field label="Titular"><span className="text-sm">{data.card_holder}</span><ActionBtns onCopy={() => copy("Titular", data.card_holder)} /></Field>}
            {data.card_expiry && <Field label="Validade"><span className="font-mono text-sm">{data.card_expiry}</span><ActionBtns onCopy={() => copy("Validade", data.card_expiry)} /></Field>}
            {data.card_cvv && (
              <Field label="CVV">
                <span className="font-mono text-sm">{reveal.cvv ? data.card_cvv : "•••"}</span>
                <ActionBtns
                  onToggle={() => setReveal((r) => ({ ...r, cvv: !r.cvv }))}
                  shown={reveal.cvv}
                  onCopy={() => copy("CVV", data.card_cvv)}
                />
              </Field>
            )}
          </>
        )}

        {data.notes && (
          <Field label="Notas">
            <span className="text-sm whitespace-pre-wrap">{data.notes}</span>
          </Field>
        )}
      </div>
    </Modal>
  );
}

function maskCard(s: string) {
  const digits = s.replace(/\s/g, "");
  return "•••• •••• •••• " + digits.slice(-4);
}

function Field({ label, children }: { label: string; children: React.ReactNode }) {
  return (
    <div className="rounded-xl border border-border bg-secondary/40 p-3">
      <div className="text-[10px] uppercase tracking-wider text-muted-foreground">{label}</div>
      <div className="mt-1 flex items-center justify-between gap-2">{children}</div>
    </div>
  );
}

function ActionBtns({ onCopy, onToggle, shown }: { onCopy?: () => void; onToggle?: () => void; shown?: boolean }) {
  return (
    <div className="flex gap-1">
      {onToggle && (
        <IconBtn onClick={onToggle} title={shown ? "Ocultar" : "Revelar"}>
          {shown ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
        </IconBtn>
      )}
      {onCopy && (
        <IconBtn onClick={onCopy} title="Copiar">
          <Copy className="h-4 w-4" />
        </IconBtn>
      )}
    </div>
  );
}

function IconBtn({ children, ...rest }: React.ButtonHTMLAttributes<HTMLButtonElement>) {
  return (
    <button {...rest} className="rounded-md p-1.5 hover:bg-secondary">
      {children}
    </button>
  );
}

/* ---------------- ITEM EDITOR ---------------- */

function ItemEditor({
  userId, categories, vaultKey, item, defaultType, onClose, onSaved,
}: {
  userId: string;
  categories: Category[];
  vaultKey: CryptoKey;
  item?: VaultItem;
  defaultType: "password" | "card";
  onClose: () => void;
  onSaved: () => void;
}) {
  const [type] = useState<"password" | "card">(item?.item_type ?? defaultType);
  const [title, setTitle] = useState(item?.title ?? "");
  const [categoryId, setCategoryId] = useState<string | null>(item?.category_id ?? null);
  const [loginUrl, setLoginUrl] = useState(item?.login_url ?? "");
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  const [notes, setNotes] = useState("");
  const [cardNumber, setCardNumber] = useState("");
  const [cardHolder, setCardHolder] = useState("");
  const [cardExpiry, setCardExpiry] = useState("");
  const [cardCvv, setCardCvv] = useState("");
  const [busy, setBusy] = useState(false);

  useEffect(() => {
    if (!item) return;
    (async () => {
      setUsername(await decryptString(vaultKey, item.username_enc));
      setPassword(await decryptString(vaultKey, item.password_enc));
      setNotes(await decryptString(vaultKey, item.notes_enc));
      setCardNumber(await decryptString(vaultKey, item.card_number_enc));
      setCardHolder(await decryptString(vaultKey, item.card_holder_enc));
      setCardExpiry(await decryptString(vaultKey, item.card_expiry_enc));
      setCardCvv(await decryptString(vaultKey, item.card_cvv_enc));
    })();
  }, [item, vaultKey]);

  const save = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!title.trim()) return toast.error("Dê um título ao item.");
    setBusy(true);
    try {
      const payload = {
        user_id: userId,
        category_id: categoryId,
        item_type: type,
        title: title.trim(),
        login_url: loginUrl.trim() || null,
        username_enc: username ? await encryptString(vaultKey, username) : null,
        password_enc: password ? await encryptString(vaultKey, password) : null,
        notes_enc: notes ? await encryptString(vaultKey, notes) : null,
        card_number_enc: cardNumber ? await encryptString(vaultKey, cardNumber) : null,
        card_holder_enc: cardHolder ? await encryptString(vaultKey, cardHolder) : null,
        card_expiry_enc: cardExpiry ? await encryptString(vaultKey, cardExpiry) : null,
        card_cvv_enc: cardCvv ? await encryptString(vaultKey, cardCvv) : null,
      };
      const { error } = item
        ? await supabase.from("vault_items").update(payload).eq("id", item.id)
        : await supabase.from("vault_items").insert(payload);
      if (error) throw error;
      toast.success(item ? "Atualizado" : "Salvo no cofre");
      onSaved();
    } catch (err) {
      toast.error((err as Error).message);
    } finally {
      setBusy(false);
    }
  };

  return (
    <Modal onClose={onClose}>
      <h2 className="font-display text-2xl">{item ? "Editar" : type === "card" ? "Novo cartão" : "Nova senha"}</h2>
      <form onSubmit={save} className="mt-4 space-y-3">
        <Input label="Título *" value={title} onChange={setTitle} placeholder={type === "card" ? "Cartão Nubank" : "Instagram"} />
        <div>
          <label className="text-xs text-muted-foreground">Categoria</label>
          <select
            value={categoryId ?? ""}
            onChange={(e) => setCategoryId(e.target.value || null)}
            className="mt-1 w-full rounded-lg border border-border bg-input px-3 py-2.5 text-sm outline-none focus:border-gold"
          >
            <option value="">Sem categoria</option>
            {categories.map((c) => (
              <option key={c.id} value={c.id}>{c.name}</option>
            ))}
          </select>
        </div>

        {type === "password" && (
          <>
            <Input label="Link da página de login" value={loginUrl} onChange={setLoginUrl} placeholder="https://..." />
            <Input label="Usuário / e-mail" value={username} onChange={setUsername} />
            <Input label="Senha" value={password} onChange={setPassword} type="password" />
          </>
        )}

        {type === "card" && (
          <>
            <Input label="Número do cartão" value={cardNumber} onChange={setCardNumber} inputMode="numeric" />
            <Input label="Nome do titular" value={cardHolder} onChange={setCardHolder} />
            <div className="grid grid-cols-2 gap-3">
              <Input label="Validade (MM/AA)" value={cardExpiry} onChange={setCardExpiry} placeholder="12/29" />
              <Input label="CVV" value={cardCvv} onChange={setCardCvv} type="password" inputMode="numeric" />
            </div>
          </>
        )}

        <div>
          <label className="text-xs text-muted-foreground">Notas</label>
          <textarea
            value={notes}
            onChange={(e) => setNotes(e.target.value)}
            rows={3}
            className="mt-1 w-full rounded-lg border border-border bg-input px-3 py-2.5 text-sm outline-none focus:border-gold"
          />
        </div>

        <div className="flex justify-end gap-2 pt-2">
          <button type="button" onClick={onClose} className="rounded-lg border border-border bg-secondary px-4 py-2 text-sm">Cancelar</button>
          <button disabled={busy} className="rounded-lg bg-gold-gradient px-4 py-2 text-sm font-semibold text-accent-foreground shadow-gold disabled:opacity-50">
            {busy ? "Salvando..." : "Salvar"}
          </button>
        </div>
      </form>
    </Modal>
  );
}

function Input({ label, value, onChange, type = "text", placeholder, inputMode }: {
  label: string;
  value: string;
  onChange: (v: string) => void;
  type?: string;
  placeholder?: string;
  inputMode?: React.HTMLAttributes<HTMLInputElement>["inputMode"];
}) {
  return (
    <div>
      <label className="text-xs text-muted-foreground">{label}</label>
      <input
        type={type}
        value={value}
        onChange={(e) => onChange(e.target.value)}
        placeholder={placeholder}
        inputMode={inputMode}
        className="mt-1 w-full rounded-lg border border-border bg-input px-3 py-2.5 text-sm outline-none focus:border-gold"
      />
    </div>
  );
}

/* ---------------- SETTINGS ---------------- */

function SettingsDialog({
  onClose, categories, onAddCategory, onDeleteCategory, newCatName, setNewCatName, reload,
}: {
  onClose: () => void;
  categories: Category[];
  onAddCategory: () => void;
  onDeleteCategory: (id: string) => void;
  newCatName: string;
  setNewCatName: (s: string) => void;
  reload: () => void;
}) {
  const { session, profile, refreshProfile } = useVault();
  const [busyBio, setBusyBio] = useState(false);
  const creds = (profile?.webauthn_credentials as Array<{ id: string }> | null) || [];
  const bioEnabled = creds.length > 0;
  const bioSupported = isBiometricSupported();

  const enableBio = async () => {
    if (!session) return;
    setBusyBio(true);
    try {
      const id = await registerBiometric(session.user.id, profile?.display_name || session.user.email || "user");
      const next = [...creds, { id }];
      const { error } = await supabase.from("profiles").update({ webauthn_credentials: next }).eq("id", session.user.id);
      if (error) throw error;
      toast.success("Biometria ativada");
      await refreshProfile();
    } catch (e) {
      toast.error((e as Error).message);
    } finally {
      setBusyBio(false);
    }
  };

  const disableBio = async () => {
    const { error } = await supabase.from("profiles").update({ webauthn_credentials: [] }).eq("id", session!.user.id);
    if (error) return toast.error(error.message);
    clearCachedPin(session!.user.id);
    toast.success("Biometria desativada");
    refreshProfile();
  };

  return (
    <Modal onClose={onClose}>
      <h2 className="font-display text-2xl">Configurações</h2>

      <section className="mt-6">
        <h3 className="text-sm font-semibold">Segurança</h3>
        <div className="mt-2 rounded-xl border border-border bg-secondary/40 p-4">
          <div className="flex items-center justify-between">
            <div>
              <div className="flex items-center gap-2"><Fingerprint className="h-4 w-4 text-gold" /> Biometria</div>
              <p className="mt-1 text-xs text-muted-foreground">
                {!bioSupported ? "Não suportado neste navegador." : bioEnabled ? "Ativa — desbloqueie com digital/Face." : "Desbloqueie o cofre com a biometria deste dispositivo."}
              </p>
            </div>
            {bioSupported && (
              bioEnabled ? (
                <button onClick={disableBio} className="rounded-md border border-border px-3 py-1.5 text-xs hover:bg-secondary">Desativar</button>
              ) : (
                <button disabled={busyBio} onClick={enableBio} className="rounded-md bg-gold-gradient px-3 py-1.5 text-xs font-semibold text-accent-foreground">
                  {busyBio ? "..." : "Ativar"}
                </button>
              )
            )}
          </div>
        </div>
        <p className="mt-2 text-xs text-muted-foreground">
          Se a biometria falhar, você sempre pode usar o PIN mestre. Recuperação por e-mail / WhatsApp para reset de PIN será adicionada em breve.
        </p>
      </section>

      <section className="mt-6">
        <h3 className="text-sm font-semibold">Categorias</h3>
        <div className="mt-2 space-y-2">
          {categories.map((c) => (
            <div key={c.id} className="flex items-center justify-between rounded-lg border border-border bg-secondary/40 px-3 py-2 text-sm">
              <div className="flex items-center gap-2">
                <span className="h-3 w-3 rounded-full" style={{ background: c.color }} />
                {c.name}
              </div>
              <button onClick={() => { onDeleteCategory(c.id); setTimeout(reload, 200); }} className="text-muted-foreground hover:text-destructive">
                <Trash2 className="h-4 w-4" />
              </button>
            </div>
          ))}
          <div className="flex gap-2">
            <input
              value={newCatName}
              onChange={(e) => setNewCatName(e.target.value)}
              placeholder="Nova categoria"
              className="flex-1 rounded-lg border border-border bg-input px-3 py-2 text-sm outline-none focus:border-gold"
            />
            <button onClick={onAddCategory} className="rounded-lg bg-emerald-gradient px-3 py-2 text-sm">
              <Plus className="h-4 w-4" />
            </button>
          </div>
        </div>
      </section>
    </Modal>
  );
}

/* ---------------- MODAL ---------------- */

function Modal({ children, onClose }: { children: React.ReactNode; onClose: () => void }) {
  useEffect(() => {
    const onKey = (e: KeyboardEvent) => e.key === "Escape" && onClose();
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onClose]);
  return (
    <div className="fixed inset-0 z-50 flex items-end justify-center bg-black/60 p-0 backdrop-blur sm:items-center sm:p-4" onClick={onClose}>
      <div onClick={(e) => e.stopPropagation()} className="relative w-full max-w-lg rounded-t-3xl border border-border bg-card p-6 shadow-vault sm:rounded-2xl">
        <button onClick={onClose} className="absolute top-3 right-3 rounded-md p-1.5 hover:bg-secondary" aria-label="Fechar">
          <X className="h-4 w-4" />
        </button>
        {children}
      </div>
    </div>
  );
}
