"use client";

import * as React from "react";
import Image from "next/image";
import { ShieldCheck, ShieldOff, Copy } from "lucide-react";
import { Checkbox } from "@/components/ui/checkbox";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import {
  InputOTP,
  InputOTPGroup,
  InputOTPSlot,
} from "@/components/ui/input-otp";
import {
  useGetTwoFactorStatusQuery,
  useGenerateTwoFactorSecretMutation,
  useEnableTwoFactorMutation,
  useDisableTwoFactorMutation,
} from "@/api/rtk/auth-api";
import { useAuthToken } from "@/hooks/use-auth-token";
import { Card, CardHeader } from "@/components/settings/ui";
import { toast } from "sonner";
import { copyTextToClipboard } from "@/lib/clipboard-write";

/** Groups base32 TOTP secret as XXXX-XXXX-… for manual entry (raw secret unchanged for API). */
function formatTotpSecretForDisplay(secret: string): string {
  const cleaned = secret.replace(/[^A-Za-z2-7]/gi, "").toUpperCase();
  if (!cleaned) return secret.trim();
  return cleaned.match(/.{1,4}/g)?.join("-") ?? cleaned;
}

export function AdminTwoFactorCard() {
  const { token } = useAuthToken();
  const { data: status, isLoading: statusLoading } = useGetTwoFactorStatusQuery(
    undefined,
    { skip: !token },
  );
  const [generateSecret, { isLoading: generating }] =
    useGenerateTwoFactorSecretMutation();
  const [enable2fa, { isLoading: enabling }] = useEnableTwoFactorMutation();
  const [disable2fa, { isLoading: disabling }] = useDisableTwoFactorMutation();

  const [wantsSetup, setWantsSetup] = React.useState(false);
  const [pendingSecret, setPendingSecret] = React.useState<string | null>(null);
  const [qrDataUrl, setQrDataUrl] = React.useState<string | null>(null);
  const [verifyCode, setVerifyCode] = React.useState("");
  const [disableCode, setDisableCode] = React.useState("");
  const [showDisable, setShowDisable] = React.useState(false);
  /** Shown once after enable — same values as DB / email (not the TOTP secret). */
  const [pendingRecovery, setPendingRecovery] = React.useState<{
    codes: string[];
    keys: string[];
  } | null>(null);

  React.useEffect(() => {
    if (status?.twoFactorEnabled) {
      setWantsSetup(false);
      setPendingSecret(null);
      setQrDataUrl(null);
      setVerifyCode("");
    }
  }, [status?.twoFactorEnabled]);

  const startSetup = async () => {
    try {
      const res = await generateSecret({ method: "app" }).unwrap();
      setPendingSecret(res.secret);
      setQrDataUrl(res.qrCodeDataUrl || null);
      setVerifyCode("");
    } catch {
      toast.error("Could not start authenticator setup. Try again.");
    }
  };

  const handleWantsSetupChange = (checked: boolean) => {
    setWantsSetup(checked);
    if (checked) {
      void startSetup();
    } else {
      setPendingSecret(null);
      setQrDataUrl(null);
      setVerifyCode("");
    }
  };

  const handleEnable = async () => {
    if (!pendingSecret || verifyCode.trim().length !== 6) {
      toast.error("Enter the 6-digit code from your authenticator app.");
      return;
    }
    try {
      const data = await enable2fa({
        secret: pendingSecret,
        token: verifyCode.trim(),
        method: "app",
      }).unwrap();
      setPendingRecovery({
        codes: data.backupCodes ?? [],
        keys: data.backupKeys ?? [],
      });
      toast.success("2FA is on. Save the recovery codes below — they also went to your email.");
      setWantsSetup(false);
      setPendingSecret(null);
      setQrDataUrl(null);
      setVerifyCode("");
    } catch {
      toast.error("Invalid code or setup failed. Try again.");
    }
  };

  const handleDisable = async () => {
    if (disableCode.trim().length !== 6) {
      toast.error("Enter your current authenticator code to turn off 2FA.");
      return;
    }
    try {
      await disable2fa({ token: disableCode.trim() }).unwrap();
      toast.success("Two-factor authentication has been disabled.");
      setShowDisable(false);
      setDisableCode("");
    } catch {
      toast.error("Invalid code. Two-factor authentication is still enabled.");
    }
  };

  if (statusLoading || !status) {
    return (
      <Card>
        <CardHeader
          title="Admin sign-in security"
          description="Loading two-factor status…"
        />
      </Card>
    );
  }

  return (
    <Card>
      <CardHeader
        title="Admin sign-in security"
        description="Require an authenticator app (TOTP) when signing in. Recommended for administrator accounts."
      />
      <div className="p-6 space-y-5">
        {status.twoFactorEnabled ? (
          <div className="space-y-4">
            {pendingRecovery &&
              (pendingRecovery.codes.length > 0 || pendingRecovery.keys.length > 0) && (
                <div className="rounded-xl border border-amber-300 bg-amber-50/90 px-4 py-3 space-y-3">
                  <p className="text-sm font-semibold text-amber-950">
                    Save these one-time login recovery codes
                  </p>
                  <p className="text-[11px] text-amber-900/90 leading-relaxed">
                    Use them only on the login screen under &quot;Backup code / key&quot; if you lose your
                    phone. They are <strong>not</strong> the same as the authenticator secret (QR / manual
                    key) — that secret only goes in your app.
                  </p>
                  {pendingRecovery.codes.length > 0 && (
                    <div>
                      <p className="text-[10px] font-bold text-amber-800 uppercase tracking-wide mb-1">
                        Short codes (3 blocks each, e.g. XXXX-XXXX-XXXX)
                      </p>
                      <ul className="font-mono text-[11px] space-y-1 text-amber-950 break-all">
                        {pendingRecovery.codes.map((c, i) => (
                          <li key={`${i}-${c}`}>{c}</li>
                        ))}
                      </ul>
                    </div>
                  )}
                  {pendingRecovery.keys.length > 0 && (
                    <div>
                      <p className="text-[10px] font-bold text-amber-800 uppercase tracking-wide mb-1">
                        Long keys (6 blocks each)
                      </p>
                      <ul className="font-mono text-[11px] space-y-1 text-amber-950 break-all">
                        {pendingRecovery.keys.map((k, i) => (
                          <li key={`${i}-${k}`}>{k}</li>
                        ))}
                      </ul>
                    </div>
                  )}
                  <div className="flex flex-wrap gap-2 pt-1">
                    <Button
                      type="button"
                      size="sm"
                      variant="outline"
                      className="border-amber-400 text-amber-950"
                      onClick={() => {
                        const text = [
                          "SalesHub 2FA recovery (one-time login)",
                          "",
                          "Codes:",
                          ...pendingRecovery.codes,
                          "",
                          "Keys:",
                          ...pendingRecovery.keys,
                        ].join("\n");
                        void copyTextToClipboard(text).then((ok) =>
                          ok
                            ? toast.success("Copied all recovery codes")
                            : toast.error(
                                "Could not copy — select the text or allow clipboard for this site.",
                              ),
                        );
                      }}
                    >
                      <Copy className="size-3.5 mr-1" />
                      Copy all
                    </Button>
                    <Button
                      type="button"
                      size="sm"
                      className="bg-amber-700 hover:bg-amber-800 text-white"
                      onClick={() => setPendingRecovery(null)}
                    >
                      I saved these
                    </Button>
                  </div>
                </div>
              )}
            <div className="flex items-start gap-3 rounded-xl border border-emerald-200 bg-emerald-50/80 px-4 py-3">
              <ShieldCheck className="h-5 w-5 text-emerald-700 shrink-0 mt-0.5" />
              <div>
                <p className="text-sm font-semibold text-emerald-900">
                  Authenticator app enabled
                </p>
                <p className="text-xs text-emerald-800/90 mt-1">
                  Method: {status.twoFactorMethod ?? "app"}. You will enter a 6-digit code after your
                  password at login.
                </p>
              </div>
            </div>
            {!showDisable ? (
              <Button
                type="button"
                variant="outline"
                size="sm"
                className="text-red-700 border-red-200 hover:bg-red-50"
                onClick={() => setShowDisable(true)}
              >
                <ShieldOff size={14} className="mr-1.5" />
                Turn off two-factor authentication
              </Button>
            ) : (
              <div className="space-y-3 rounded-xl border border-gray-200 bg-gray-50/60 p-4">
                <Label className="text-xs font-semibold text-gray-700">
                  Enter a code from your authenticator app to confirm
                </Label>
                <InputOTP
                  maxLength={6}
                  value={disableCode}
                  onChange={(v) => setDisableCode(v.replace(/\D/g, ""))}
                >
                  <InputOTPGroup className="gap-2">
                    <InputOTPSlot index={0} className="h-10 w-9 rounded-lg" />
                    <InputOTPSlot index={1} className="h-10 w-9 rounded-lg" />
                    <InputOTPSlot index={2} className="h-10 w-9 rounded-lg" />
                    <InputOTPSlot index={3} className="h-10 w-9 rounded-lg" />
                    <InputOTPSlot index={4} className="h-10 w-9 rounded-lg" />
                    <InputOTPSlot index={5} className="h-10 w-9 rounded-lg" />
                  </InputOTPGroup>
                </InputOTP>
                <div className="flex gap-2">
                  <Button
                    type="button"
                    size="sm"
                    variant="destructive"
                    disabled={disabling || disableCode.trim().length !== 6}
                    onClick={() => void handleDisable()}
                  >
                    {disabling ? "Removing…" : "Confirm disable"}
                  </Button>
                  <Button
                    type="button"
                    size="sm"
                    variant="ghost"
                    onClick={() => {
                      setShowDisable(false);
                      setDisableCode("");
                    }}
                  >
                    Cancel
                  </Button>
                </div>
              </div>
            )}
          </div>
        ) : (
          <div className="space-y-4">
            <div className="flex items-start gap-3">
              <Checkbox
                id="admin-2fa-enable"
                checked={wantsSetup}
                onCheckedChange={(c) => handleWantsSetupChange(c === true)}
                disabled={generating}
                className="mt-0.5 border-gray-300 data-[state=checked]:bg-[#6C63FF] data-[state=checked]:border-[#6C63FF]"
              />
              <div className="space-y-1">
                <Label
                  htmlFor="admin-2fa-enable"
                  className="text-sm font-medium text-gray-900 cursor-pointer"
                >
                  Enable two-factor authentication (authenticator app)
                </Label>
                <p className="text-xs text-gray-500">
                  Scan the QR code with Google Authenticator, Authy, or another TOTP app, then confirm
                  with a 6-digit code.
                </p>
              </div>
            </div>

            {wantsSetup && pendingSecret && (
              <div className="space-y-4 rounded-xl border border-gray-200 bg-white p-4">
                {qrDataUrl ? (
                  <div className="flex flex-col items-center gap-2">
                    <Image
                      src={qrDataUrl}
                      alt="QR code for authenticator setup"
                      width={176}
                      height={176}
                      unoptimized
                      className="rounded-lg border border-gray-100"
                    />
                    <p className="text-[11px] text-gray-500 text-center max-w-sm">
                      Scan this QR code, or enter the secret manually in your app.
                    </p>
                  </div>
                ) : null}
                <div>
                  <div className="flex items-center justify-between gap-2">
                    <Label className="text-xs text-gray-500">Secret key (manual entry)</Label>
                    <Button
                      type="button"
                      variant="ghost"
                      size="sm"
                      className="h-7 px-2 text-[11px] text-[#6C63FF] shrink-0"
                      onClick={() => {
                        void copyTextToClipboard(pendingSecret).then((ok) =>
                          ok
                            ? toast.success(
                                "Secret copied (no dashes — ready to paste in your app)",
                              )
                            : toast.error(
                                "Could not copy — allow clipboard for this site or copy manually.",
                              ),
                        );
                      }}
                    >
                      <Copy className="size-3.5 mr-1" />
                      Copy raw
                    </Button>
                  </div>
                  <Input
                    readOnly
                    value={formatTotpSecretForDisplay(pendingSecret)}
                    className="mt-1 font-mono text-xs h-9 bg-gray-50 tracking-wide"
                  />
                  <p className="text-[10px] text-gray-400 mt-1">
                    Dashes are only for readability. Your app accepts the same key with or without them.
                    This is <strong>not</strong> a backup login code — recovery codes appear only after you
                    confirm below (and in your email).
                  </p>
                </div>
                <div>
                  <Label className="text-xs font-semibold text-gray-700">
                    Verification code
                  </Label>
                  <div className="flex justify-center mt-2">
                    <InputOTP
                      maxLength={6}
                      value={verifyCode}
                      onChange={(v) => setVerifyCode(v.replace(/\D/g, ""))}
                    >
                      <InputOTPGroup className="gap-2">
                        <InputOTPSlot index={0} className="h-10 w-9 rounded-lg" />
                        <InputOTPSlot index={1} className="h-10 w-9 rounded-lg" />
                        <InputOTPSlot index={2} className="h-10 w-9 rounded-lg" />
                        <InputOTPSlot index={3} className="h-10 w-9 rounded-lg" />
                        <InputOTPSlot index={4} className="h-10 w-9 rounded-lg" />
                        <InputOTPSlot index={5} className="h-10 w-9 rounded-lg" />
                      </InputOTPGroup>
                    </InputOTP>
                  </div>
                </div>
                <Button
                  type="button"
                  className="w-full bg-[#6C63FF] hover:bg-[#5b52e0] text-white"
                  disabled={enabling || verifyCode.trim().length !== 6}
                  onClick={() => void handleEnable()}
                >
                  {enabling ? "Enabling…" : "Confirm and enable 2FA"}
                </Button>
              </div>
            )}
          </div>
        )}
      </div>
    </Card>
  );
}
