// src/components/two-factor-settings.tsx — "Sécurité" card on settings/account.
// Enroll into TOTP 2FA (password → QR + backup codes → confirm with a code) or
// disable it (password). Uses the Better Auth twoFactor client plugin.
"use client";

import { CheckCircle2Icon, CopyIcon, ShieldCheckIcon } from "lucide-react";
import { useTranslations } from "next-intl";
import { QRCodeSVG } from "qrcode.react";
import { useState } from "react";
import { toast } from "sonner";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
  Card,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Field, FieldLabel } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
import { authClient } from "@/lib/auth-client";

// Pull the raw `secret` out of an otpauth:// URI for manual authenticator entry
// (fallback when the QR can't be scanned).
function secretFromUri(uri: string): string | null {
  try {
    return new URL(uri).searchParams.get("secret");
  } catch {
    return null;
  }
}

export function TwoFactorSettings({
  enabled,
  onEnabled,
}: {
  enabled: boolean;
  /** Fired after a successful enrollment — e.g. the /staff-2fa gate uses it to
   *  move the operator on to /admin once 2FA is live. */
  onEnabled?: () => void;
}) {
  const t = useTranslations("TwoFactor");
  const [isEnabled, setIsEnabled] = useState(enabled);
  const [enrollOpen, setEnrollOpen] = useState(false);
  const [disableOpen, setDisableOpen] = useState(false);

  return (
    <Card>
      <CardHeader>
        <CardTitle className="flex items-center gap-2">
          <ShieldCheckIcon className="size-[18px]" />
          {t("cardTitle")}
        </CardTitle>
        <CardDescription>{t("cardDescription")}</CardDescription>
      </CardHeader>
      <CardContent>
        {isEnabled ? (
          <div className="flex items-center gap-2 text-sm">
            <Badge
              variant="secondary"
              className="border-emerald-500/30 bg-emerald-500/15 text-emerald-700 dark:text-emerald-400"
            >
              <CheckCircle2Icon className="size-3.5" />
              {t("statusEnabled")}
            </Badge>
            <span className="text-muted-foreground">{t("enabledHint")}</span>
          </div>
        ) : (
          <p className="text-muted-foreground text-sm">{t("statusDisabled")}</p>
        )}
      </CardContent>
      <CardFooter className="justify-end">
        {isEnabled ? (
          <Button variant="outline" onClick={() => setDisableOpen(true)}>
            {t("disableButton")}
          </Button>
        ) : (
          <Button onClick={() => setEnrollOpen(true)}>
            {t("enableButton")}
          </Button>
        )}
      </CardFooter>

      <EnrollDialog
        open={enrollOpen}
        onOpenChange={setEnrollOpen}
        onEnabled={() => {
          setIsEnabled(true);
          onEnabled?.();
        }}
      />
      <DisableDialog
        open={disableOpen}
        onOpenChange={setDisableOpen}
        onDisabled={() => setIsEnabled(false)}
      />
    </Card>
  );
}

type Enrollment = { totpURI: string; backupCodes: string[] };

function EnrollDialog({
  open,
  onOpenChange,
  onEnabled,
}: {
  open: boolean;
  onOpenChange: (v: boolean) => void;
  onEnabled: () => void;
}) {
  const t = useTranslations("TwoFactor");
  // "password" → ask password & call enable; "verify" → show QR/codes & confirm.
  const [step, setStep] = useState<"password" | "verify">("password");
  const [password, setPassword] = useState("");
  const [code, setCode] = useState("");
  const [enrollment, setEnrollment] = useState<Enrollment | null>(null);
  const [pending, setPending] = useState(false);
  const [error, setError] = useState<string | null>(null);

  function reset() {
    setStep("password");
    setPassword("");
    setCode("");
    setEnrollment(null);
    setPending(false);
    setError(null);
  }

  async function startEnroll(e: React.FormEvent) {
    e.preventDefault();
    setPending(true);
    setError(null);
    // enable() returns the otpauth URI + one-time backup codes. 2FA is NOT yet
    // active — the user must confirm a code first (skipVerificationOnEnable=false).
    const res = await authClient.twoFactor.enable({ password });
    setPending(false);
    if (res.error) {
      setError(res.error.message ?? t("enableFailed"));
      return;
    }
    setEnrollment(res.data);
    setStep("verify");
  }

  async function confirm(e: React.FormEvent) {
    e.preventDefault();
    setPending(true);
    setError(null);
    const res = await authClient.twoFactor.verifyTotp({ code: code.trim() });
    setPending(false);
    if (res.error) {
      setError(res.error.message ?? t("invalidCode"));
      return;
    }
    toast.success(t("enabledToast"));
    onEnabled();
    onOpenChange(false);
    reset();
  }

  const secret = enrollment ? secretFromUri(enrollment.totpURI) : null;

  return (
    <Dialog
      open={open}
      onOpenChange={(v) => {
        onOpenChange(v);
        if (!v) reset();
      }}
    >
      <DialogContent className="sm:max-w-md">
        {step === "password" ? (
          <form onSubmit={startEnroll}>
            <DialogHeader>
              <DialogTitle>{t("enrollTitle")}</DialogTitle>
              <DialogDescription>{t("enrollPasswordPrompt")}</DialogDescription>
            </DialogHeader>
            <div className="py-4">
              <Field>
                <FieldLabel htmlFor="tf-enroll-password">
                  {t("passwordLabel")}
                </FieldLabel>
                <Input
                  id="tf-enroll-password"
                  type="password"
                  value={password}
                  onChange={(e) => setPassword(e.target.value)}
                  autoComplete="current-password"
                  required
                />
              </Field>
              {error ? (
                <p className="mt-3 text-destructive text-sm" role="alert">
                  {error}
                </p>
              ) : null}
            </div>
            <DialogFooter>
              <Button
                type="button"
                variant="outline"
                onClick={() => onOpenChange(false)}
              >
                {t("cancel")}
              </Button>
              <Button type="submit" disabled={pending || !password}>
                {pending ? "…" : t("continue")}
              </Button>
            </DialogFooter>
          </form>
        ) : (
          <form onSubmit={confirm}>
            <DialogHeader>
              <DialogTitle>{t("scanTitle")}</DialogTitle>
              <DialogDescription>{t("scanPrompt")}</DialogDescription>
            </DialogHeader>
            <div className="flex flex-col gap-4 py-4">
              {enrollment ? (
                <div className="flex justify-center rounded-lg border bg-white p-4">
                  <QRCodeSVG value={enrollment.totpURI} size={168} />
                </div>
              ) : null}
              {secret ? (
                <div className="flex flex-col gap-1.5">
                  <span className="text-muted-foreground text-xs">
                    {t("manualEntry")}
                  </span>
                  <CopyableCode value={secret} label={t("copySecret")} />
                </div>
              ) : null}

              {enrollment ? (
                <div className="flex flex-col gap-2 rounded-lg border border-amber-500/40 bg-amber-500/[0.06] p-3">
                  <span className="font-medium text-sm">
                    {t("backupCodesTitle")}
                  </span>
                  <span className="text-muted-foreground text-xs">
                    {t("backupCodesWarning")}
                  </span>
                  <div className="grid grid-cols-2 gap-1.5 pt-1 font-mono text-sm">
                    {enrollment.backupCodes.map((c) => (
                      <span key={c}>{c}</span>
                    ))}
                  </div>
                  <CopyableCode
                    value={enrollment.backupCodes.join("\n")}
                    label={t("copyBackupCodes")}
                    className="mt-1 w-fit"
                  />
                </div>
              ) : null}

              <Field>
                <FieldLabel htmlFor="tf-confirm-code">
                  {t("confirmCodeLabel")}
                </FieldLabel>
                <Input
                  id="tf-confirm-code"
                  value={code}
                  onChange={(e) => setCode(e.target.value)}
                  inputMode="numeric"
                  autoComplete="one-time-code"
                  placeholder={t("codePlaceholder")}
                  required
                />
              </Field>
              {error ? (
                <p className="text-destructive text-sm" role="alert">
                  {error}
                </p>
              ) : null}
            </div>
            <DialogFooter>
              <Button type="submit" disabled={pending || !code.trim()}>
                {pending ? "…" : t("confirmButton")}
              </Button>
            </DialogFooter>
          </form>
        )}
      </DialogContent>
    </Dialog>
  );
}

function DisableDialog({
  open,
  onOpenChange,
  onDisabled,
}: {
  open: boolean;
  onOpenChange: (v: boolean) => void;
  onDisabled: () => void;
}) {
  const t = useTranslations("TwoFactor");
  const [password, setPassword] = useState("");
  const [pending, setPending] = useState(false);
  const [error, setError] = useState<string | null>(null);

  async function submit(e: React.FormEvent) {
    e.preventDefault();
    setPending(true);
    setError(null);
    const res = await authClient.twoFactor.disable({ password });
    setPending(false);
    if (res.error) {
      setError(res.error.message ?? t("disableFailed"));
      return;
    }
    toast.success(t("disabledToast"));
    onDisabled();
    onOpenChange(false);
    setPassword("");
  }

  return (
    <Dialog
      open={open}
      onOpenChange={(v) => {
        onOpenChange(v);
        if (!v) {
          setPassword("");
          setError(null);
        }
      }}
    >
      <DialogContent className="sm:max-w-md">
        <form onSubmit={submit}>
          <DialogHeader>
            <DialogTitle>{t("disableTitle")}</DialogTitle>
            <DialogDescription>{t("disablePrompt")}</DialogDescription>
          </DialogHeader>
          <div className="py-4">
            <Field>
              <FieldLabel htmlFor="tf-disable-password">
                {t("passwordLabel")}
              </FieldLabel>
              <Input
                id="tf-disable-password"
                type="password"
                value={password}
                onChange={(e) => setPassword(e.target.value)}
                autoComplete="current-password"
                required
              />
            </Field>
            {error ? (
              <p className="mt-3 text-destructive text-sm" role="alert">
                {error}
              </p>
            ) : null}
          </div>
          <DialogFooter>
            <Button
              type="button"
              variant="outline"
              onClick={() => onOpenChange(false)}
            >
              {t("cancel")}
            </Button>
            <Button
              type="submit"
              variant="destructive"
              disabled={pending || !password}
            >
              {pending ? "…" : t("disableButton")}
            </Button>
          </DialogFooter>
        </form>
      </DialogContent>
    </Dialog>
  );
}

function CopyableCode({
  value,
  label,
  className,
}: {
  value: string;
  label: string;
  className?: string;
}) {
  return (
    <Button
      type="button"
      variant="outline"
      size="sm"
      className={className}
      onClick={() => {
        void navigator.clipboard.writeText(value);
        toast.success(label);
      }}
    >
      <CopyIcon className="size-3.5" />
      {label}
    </Button>
  );
}
