"use client";

import { useState } from "react";
import { useToastStore } from "@/lib/stores/toast-store";

// R14 E.5: enroll / disable flow for TOTP 2FA. The QR code is rendered as
// a Google Charts-style URL for simplicity (no QR library shipped to the
// client); users with a working authenticator app can also paste the
// secret manually.

interface Props {
  initiallyEnabled: boolean;
}

export default function TwoFactorSetup({ initiallyEnabled }: Props) {
  const [enabled, setEnabled] = useState(initiallyEnabled);
  const [phase, setPhase] = useState<"idle" | "enrolling" | "disabling" | "recovery-codes">("idle");
  const [otpauthUrl, setOtpauthUrl] = useState<string | null>(null);
  const [secret, setSecret] = useState<string | null>(null);
  const [code, setCode] = useState("");
  const [busy, setBusy] = useState(false);
  // R15 B.1: returned ONCE from /verify; user must save them. They are
  // hashed server-side and not retrievable later.
  const [recoveryCodes, setRecoveryCodes] = useState<string[] | null>(null);
  const addToast = useToastStore((s) => s.addToast);

  async function handleStartEnroll() {
    setBusy(true);
    try {
      const res = await fetch("/api/auth/2fa/setup", { method: "POST" });
      if (!res.ok) {
        const data = await res.json().catch(() => ({}));
        addToast("error", data.error || "Couldn't start 2FA setup");
        return;
      }
      const data = await res.json();
      setOtpauthUrl(data.otpauth_url);
      setSecret(data.secret);
      setPhase("enrolling");
    } finally {
      setBusy(false);
    }
  }

  async function handleVerify(e: React.FormEvent) {
    e.preventDefault();
    if (!/^\d{6}$/.test(code)) {
      addToast("error", "Code must be 6 digits");
      return;
    }
    setBusy(true);
    try {
      const res = await fetch("/api/auth/2fa/verify", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ code }),
      });
      const data = await res.json().catch(() => ({}));
      if (res.ok) {
        addToast("success", "Two-factor authentication enabled.");
        setEnabled(true);
        setOtpauthUrl(null);
        setSecret(null);
        setCode("");
        if (Array.isArray(data.recovery_codes) && data.recovery_codes.length > 0) {
          setRecoveryCodes(data.recovery_codes);
          setPhase("recovery-codes");
        } else {
          setPhase("idle");
        }
      } else {
        addToast("error", data.error || "Invalid code");
      }
    } finally {
      setBusy(false);
    }
  }

  async function handleDisable(e: React.FormEvent) {
    e.preventDefault();
    // R15 B.1: accept either a 6-digit TOTP code or a recovery code.
    const trimmed = code.trim();
    const looksLikeTotp = /^\d{6}$/.test(trimmed);
    const looksLikeRecovery = /^[A-Za-z0-9]{4}-?[A-Za-z0-9]{4}-?[A-Za-z0-9]{4}$/.test(trimmed);
    if (!looksLikeTotp && !looksLikeRecovery) {
      addToast("error", "Enter a 6-digit code or a recovery code (e.g. ABCD-EFGH-JKLM)");
      return;
    }
    setBusy(true);
    try {
      const res = await fetch("/api/auth/2fa/disable", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(
          looksLikeTotp ? { code: trimmed } : { recovery_code: trimmed },
        ),
      });
      const data = await res.json().catch(() => ({}));
      if (res.ok) {
        addToast("success", "Two-factor authentication disabled.");
        setEnabled(false);
        setPhase("idle");
        setCode("");
      } else {
        addToast("error", data.error || "Invalid code");
      }
    } finally {
      setBusy(false);
    }
  }

  // Google Charts QR endpoint — keeps the bundle small. otpauth_url is the
  // standard otpauth:// URI; pasted into authenticator apps via QR scan.
  const qrSrc = otpauthUrl
    ? `https://chart.googleapis.com/chart?chs=200x200&cht=qr&choe=UTF-8&chl=${encodeURIComponent(otpauthUrl)}`
    : null;

  if (phase === "recovery-codes" && recoveryCodes) {
    return (
      <div className="space-y-3">
        <div className="bg-amber-500/10 border border-amber-500/40 text-amber-200 rounded p-3 text-sm">
          <strong className="block mb-1">Save these recovery codes.</strong>
          You can use one to disable 2FA if you lose your authenticator app.
          They are shown only once and are not recoverable.
        </div>
        <ul className="grid grid-cols-2 gap-2 font-mono text-sm bg-surface-light rounded p-3">
          {recoveryCodes.map((c) => (
            <li key={c} className="text-text">{c}</li>
          ))}
        </ul>
        <div className="flex gap-2">
          <button
            type="button"
            onClick={() => {
              navigator.clipboard?.writeText(recoveryCodes.join("\n"));
              addToast("success", "Recovery codes copied.");
            }}
            className="bg-surface-light hover:bg-surface text-text px-4 py-2 rounded-lg text-sm transition-colors"
          >
            Copy codes
          </button>
          <button
            type="button"
            onClick={() => {
              setRecoveryCodes(null);
              setPhase("idle");
            }}
            className="bg-primary hover:bg-primary-dark text-white px-4 py-2 rounded-lg text-sm font-semibold transition-colors"
          >
            I've saved them
          </button>
        </div>
      </div>
    );
  }

  if (enabled && phase !== "disabling") {
    return (
      <div className="space-y-3">
        <p className="text-sm text-text-muted">
          Two-factor authentication is active. You&apos;ll be prompted for a
          6-digit code on every sign-in.
        </p>
        <button
          type="button"
          onClick={() => setPhase("disabling")}
          className="bg-red-600/20 border border-red-600/30 hover:bg-red-600/30 text-red-300 px-4 py-2 rounded-lg text-sm font-medium transition-colors"
        >
          Disable 2FA
        </button>
      </div>
    );
  }

  if (phase === "disabling") {
    return (
      <form onSubmit={handleDisable} className="space-y-3">
        <p className="text-sm text-text-muted">
          Enter the current 6-digit code from your authenticator app, or a
          recovery code, to turn off 2FA.
        </p>
        <input
          type="text"
          inputMode="text"
          maxLength={20}
          value={code}
          onChange={(e) => setCode(e.target.value.toUpperCase().replace(/[^A-Z0-9-]/g, "").slice(0, 20))}
          placeholder="123456 or ABCD-EFGH-JKLM"
          autoComplete="one-time-code"
          className="w-64 bg-background border border-surface-light rounded-lg px-4 py-2.5 text-text font-mono text-base tracking-wider focus:outline-none focus:ring-2 focus:ring-primary"
        />
        <div className="flex gap-2">
          <button
            type="submit"
            disabled={busy}
            className="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-lg text-sm font-semibold transition-colors disabled:opacity-50"
          >
            {busy ? "Disabling…" : "Confirm disable"}
          </button>
          <button
            type="button"
            onClick={() => {
              setPhase("idle");
              setCode("");
            }}
            className="bg-surface-light hover:bg-surface text-text-muted px-4 py-2 rounded-lg text-sm transition-colors"
          >
            Cancel
          </button>
        </div>
      </form>
    );
  }

  if (phase === "enrolling" && qrSrc && secret) {
    return (
      <div className="space-y-4">
        <p className="text-sm text-text-muted">
          Scan this QR code with your authenticator app (Google Authenticator,
          Authy, 1Password, etc.) — or paste the secret manually.
        </p>
        <div className="flex flex-col sm:flex-row gap-4 items-start">
          {/* eslint-disable-next-line @next/next/no-img-element */}
          <img src={qrSrc} alt="2FA QR code" width={200} height={200} className="rounded-lg bg-white p-2" />
          <div className="space-y-2 flex-1">
            <p className="text-xs text-text-muted">Or paste this secret:</p>
            <code className="block bg-surface-light text-text font-mono text-xs px-3 py-2 rounded break-all">
              {secret}
            </code>
          </div>
        </div>
        <form onSubmit={handleVerify} className="space-y-3">
          <label className="block text-sm font-medium text-text">
            Enter the 6-digit code from your app to confirm:
          </label>
          <input
            type="text"
            inputMode="numeric"
            pattern="[0-9]{6}"
            maxLength={6}
            value={code}
            onChange={(e) => setCode(e.target.value.replace(/\D/g, "").slice(0, 6))}
            placeholder="123456"
            autoComplete="one-time-code"
            className="w-32 bg-background border border-surface-light rounded-lg px-4 py-2.5 text-text font-mono text-lg tracking-widest focus:outline-none focus:ring-2 focus:ring-primary"
          />
          <div className="flex gap-2">
            <button
              type="submit"
              disabled={busy}
              className="bg-primary hover:bg-primary-dark text-white px-4 py-2 rounded-lg text-sm font-semibold transition-colors disabled:opacity-50"
            >
              {busy ? "Verifying…" : "Enable 2FA"}
            </button>
            <button
              type="button"
              onClick={() => {
                setPhase("idle");
                setOtpauthUrl(null);
                setSecret(null);
                setCode("");
              }}
              className="bg-surface-light hover:bg-surface text-text-muted px-4 py-2 rounded-lg text-sm transition-colors"
            >
              Cancel
            </button>
          </div>
        </form>
      </div>
    );
  }

  return (
    <button
      type="button"
      onClick={handleStartEnroll}
      disabled={busy}
      className="bg-primary hover:bg-primary-dark text-white px-5 py-2.5 rounded-lg font-semibold transition-colors disabled:opacity-50"
    >
      {busy ? "Starting…" : "Enable 2FA"}
    </button>
  );
}
