'use client'

import { useId, useRef, useState } from 'react'
import { QRCodeSVG } from 'qrcode.react'
import { toast } from 'sonner'
import {
  AlertTriangle,
  Check,
  Copy,
  Download,
  Loader2,
  ShieldCheck,
  ShieldAlert,
} from 'lucide-react'
import { SecurityCard, StatusRow } from '../settings/securityPrimitives.js'
import { useMfaEnrollment } from './useMfaEnrollment.js'

type SetupStep = 'idle' | 'reauth' | 'enroll'

function FieldError({ id, message }: { id: string; message: string | null }) {
  if (!message) return null
  return (
    <p id={id} role="alert" className="text-destructive mt-1.5 text-sm">
      {message}
    </p>
  )
}

export function AccountSecurity() {
  const headingId = useId()
  const pwId = useId()
  const pwErrId = useId()
  const codeId = useId()
  const codeErrId = useId()
  const disablePwId = useId()
  const disableErrId = useId()

  const mfa = useMfaEnrollment()

  const [step, setStep] = useState<SetupStep>('idle')
  const [password, setPassword] = useState('')
  const [verifyCode, setVerifyCode] = useState('')
  const [setupError, setSetupError] = useState<string | null>(null)
  const [codeError, setCodeError] = useState<string | null>(null)
  const [savedAcknowledged, setSavedAcknowledged] = useState(false)

  const [disabling, setDisabling] = useState(false)
  const [disablePassword, setDisablePassword] = useState('')
  const [disableError, setDisableError] = useState<string | null>(null)
  const codeInputRef = useRef<HTMLInputElement>(null)

  function resetSetup() {
    mfa.cancelSetup()
    setStep('idle')
    setPassword('')
    setVerifyCode('')
    setSetupError(null)
    setCodeError(null)
    setSavedAcknowledged(false)
  }

  async function handleBeginSetup() {
    setSetupError(null)
    const result = await mfa.beginSetup(password)
    if (!result.ok) {
      setSetupError(result.error ?? 'Could not start MFA setup.')
      return
    }
    setPassword('')
    setStep('enroll')
    // Move focus to the code field once the QR is shown.
    requestAnimationFrame(() => codeInputRef.current?.focus())
  }

  async function handleConfirmSetup() {
    setCodeError(null)
    const result = await mfa.confirmSetup(verifyCode)
    if (!result.ok) {
      setCodeError(result.error ?? 'That code did not match. Try the current one.')
      return
    }
    toast.success('Two-factor authentication is now enabled.')
    resetSetup()
  }

  async function handleDisable() {
    setDisableError(null)
    const result = await mfa.disable(disablePassword)
    if (!result.ok) {
      setDisableError(result.error ?? 'Could not disable MFA.')
      return
    }
    toast.success('Two-factor authentication has been disabled.')
    setDisabling(false)
    setDisablePassword('')
  }

  function copyBackupCodes() {
    if (!mfa.enrollment) return
    void navigator.clipboard
      ?.writeText(mfa.enrollment.backupCodes.join('\n'))
      .then(() => toast.success('Backup codes copied to clipboard.'))
      .catch(() => toast.error('Could not copy codes. Copy them manually.'))
  }

  function downloadBackupCodes() {
    if (!mfa.enrollment) return
    const blob = new Blob(
      [
        'Actuate CMS — two-factor backup codes\n',
        'Each code can be used once if you lose access to your authenticator app.\n\n',
        mfa.enrollment.backupCodes.join('\n'),
        '\n',
      ],
      { type: 'text/plain' },
    )
    const url = URL.createObjectURL(blob)
    const a = document.createElement('a')
    a.href = url
    a.download = 'actuate-backup-codes.txt'
    a.click()
    URL.revokeObjectURL(url)
  }

  return (
    <SecurityCard
      headingId={headingId}
      title="Two-factor authentication"
      description="Add a one-time code from an authenticator app to your sign-in for an extra layer of protection."
    >
      {mfa.status === 'loading' && (
        <div className="text-muted-foreground flex items-center gap-2 text-sm">
          <Loader2 size={16} className="animate-spin" aria-hidden="true" />
          Checking your MFA status…
        </div>
      )}

      {mfa.status === 'error' && (
        <div className="flex items-center justify-between gap-3">
          <p className="text-muted-foreground text-sm">Could not load your MFA status.</p>
          <button
            type="button"
            onClick={() => void mfa.refresh()}
            className="border-border text-foreground hover:bg-accent rounded-md border px-3 py-1.5 text-sm transition-colors"
          >
            Retry
          </button>
        </div>
      )}

      {/* ── Enabled ─────────────────────────────────────────────── */}
      {mfa.status === 'enabled' && (
        <div className="space-y-4">
          <StatusRow status="pass" label="Two-factor authentication" value="Enabled" />
          {!disabling ? (
            <button
              type="button"
              onClick={() => {
                setDisabling(true)
                setDisableError(null)
              }}
              className="border-border text-foreground hover:bg-accent inline-flex items-center gap-2 rounded-md border px-3 py-2 text-sm transition-colors"
            >
              <ShieldAlert size={16} aria-hidden="true" />
              Disable two-factor
            </button>
          ) : (
            <div className="border-destructive/30 bg-destructive/5 space-y-3 rounded-md border p-3">
              <div className="flex items-start gap-2">
                <AlertTriangle
                  size={16}
                  className="text-destructive mt-0.5 shrink-0"
                  aria-hidden="true"
                />
                <p className="text-foreground text-sm">
                  Disabling two-factor makes your account password-only and signs out your other
                  sessions. Confirm your password to continue.
                </p>
              </div>
              <div>
                <label
                  htmlFor={disablePwId}
                  className="text-foreground mb-1 block text-sm font-medium"
                >
                  Current password
                </label>
                <input
                  id={disablePwId}
                  type="password"
                  autoComplete="current-password"
                  value={disablePassword}
                  onChange={(e) => setDisablePassword(e.target.value)}
                  aria-invalid={disableError ? true : undefined}
                  aria-describedby={disableError ? disableErrId : undefined}
                  className="border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-3 py-2 text-sm focus-visible:ring-2 focus-visible:outline-none"
                />
                <FieldError id={disableErrId} message={disableError} />
              </div>
              <div className="flex items-center justify-end gap-3">
                <button
                  type="button"
                  onClick={() => {
                    setDisabling(false)
                    setDisablePassword('')
                    setDisableError(null)
                  }}
                  className="text-muted-foreground hover:text-foreground rounded-md px-3 py-2 text-sm transition-colors"
                >
                  Cancel
                </button>
                <button
                  type="button"
                  onClick={() => void handleDisable()}
                  disabled={mfa.busy || !disablePassword}
                  className="bg-destructive text-destructive-foreground inline-flex items-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50"
                >
                  {mfa.busy && <Loader2 size={16} className="animate-spin" aria-hidden="true" />}
                  Disable two-factor
                </button>
              </div>
            </div>
          )}
        </div>
      )}

      {/* ── Disabled: idle ──────────────────────────────────────── */}
      {mfa.status === 'disabled' && step === 'idle' && (
        <div className="space-y-4">
          <StatusRow status="warning" label="Two-factor authentication" value="Not set up" />
          <button
            type="button"
            onClick={() => {
              setStep('reauth')
              setSetupError(null)
            }}
            className="bg-brand text-brand-foreground focus-visible:ring-ring inline-flex items-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-opacity hover:opacity-90 focus-visible:ring-2 focus-visible:outline-none"
          >
            <ShieldCheck size={16} aria-hidden="true" />
            Set up two-factor
          </button>
        </div>
      )}

      {/* ── Disabled: reauth ────────────────────────────────────── */}
      {mfa.status === 'disabled' && step === 'reauth' && (
        <div className="space-y-3">
          <p className="text-muted-foreground text-sm">
            Confirm your current password to begin setting up two-factor authentication.
          </p>
          <div>
            <label htmlFor={pwId} className="text-foreground mb-1 block text-sm font-medium">
              Current password
            </label>
            <input
              id={pwId}
              type="password"
              autoComplete="current-password"
              value={password}
              onChange={(e) => setPassword(e.target.value)}
              autoFocus
              aria-invalid={setupError ? true : undefined}
              aria-describedby={setupError ? pwErrId : undefined}
              onKeyDown={(e) => {
                if (e.key === 'Enter' && password && !mfa.busy) void handleBeginSetup()
              }}
              className="border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-3 py-2 text-sm focus-visible:ring-2 focus-visible:outline-none"
            />
            <FieldError id={pwErrId} message={setupError} />
          </div>
          <div className="flex items-center justify-end gap-3">
            <button
              type="button"
              onClick={resetSetup}
              className="text-muted-foreground hover:text-foreground rounded-md px-3 py-2 text-sm transition-colors"
            >
              Cancel
            </button>
            <button
              type="button"
              onClick={() => void handleBeginSetup()}
              disabled={mfa.busy || !password}
              className="bg-brand text-brand-foreground inline-flex items-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50"
            >
              {mfa.busy && <Loader2 size={16} className="animate-spin" aria-hidden="true" />}
              Continue
            </button>
          </div>
        </div>
      )}

      {/* ── Disabled: enroll (QR + backup codes + verify) ───────── */}
      {mfa.status === 'disabled' && step === 'enroll' && mfa.enrollment && (
        <div className="space-y-5">
          <ol className="text-foreground list-decimal space-y-4 pl-5 text-sm">
            <li>
              <p className="font-medium">Scan this QR code with your authenticator app.</p>
              <div className="border-border mt-2 inline-flex rounded-lg border bg-white p-3">
                <QRCodeSVG
                  value={mfa.enrollment.uri}
                  size={160}
                  role="img"
                  aria-label="Two-factor setup QR code"
                />
              </div>
              <p className="text-muted-foreground mt-2">
                Can&apos;t scan? Enter this key manually:
              </p>
              <code className="border-border bg-muted text-foreground mt-1 inline-block rounded border px-2 py-1 font-mono text-xs break-all">
                {mfa.enrollment.secret}
              </code>
            </li>
            <li>
              <p className="font-medium">Save your backup codes.</p>
              <p className="text-muted-foreground mt-0.5">
                Each code works once if you lose your authenticator. They won&apos;t be shown again.
              </p>
              <ul className="border-border bg-muted/40 mt-2 grid grid-cols-2 gap-x-6 gap-y-1 rounded-md border p-3 font-mono text-xs sm:grid-cols-4">
                {mfa.enrollment.backupCodes.map((code) => (
                  <li key={code} className="text-foreground">
                    {code}
                  </li>
                ))}
              </ul>
              <div className="mt-2 flex flex-wrap gap-2">
                <button
                  type="button"
                  onClick={copyBackupCodes}
                  className="border-border text-foreground hover:bg-accent inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-xs transition-colors"
                >
                  <Copy size={14} aria-hidden="true" />
                  Copy codes
                </button>
                <button
                  type="button"
                  onClick={downloadBackupCodes}
                  className="border-border text-foreground hover:bg-accent inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-xs transition-colors"
                >
                  <Download size={14} aria-hidden="true" />
                  Download
                </button>
              </div>
              <label className="text-foreground mt-2 flex items-center gap-2 text-sm">
                <input
                  type="checkbox"
                  checked={savedAcknowledged}
                  onChange={(e) => setSavedAcknowledged(e.target.checked)}
                  className="accent-brand h-4 w-4"
                />
                I&apos;ve saved my backup codes somewhere safe.
              </label>
            </li>
            <li>
              <p className="font-medium">Enter the 6-digit code from your app to finish.</p>
              <div className="mt-2">
                <label htmlFor={codeId} className="sr-only">
                  Authentication code
                </label>
                <input
                  id={codeId}
                  ref={codeInputRef}
                  inputMode="numeric"
                  autoComplete="one-time-code"
                  maxLength={6}
                  placeholder="123456"
                  value={verifyCode}
                  onChange={(e) => setVerifyCode(e.target.value.replace(/\D/g, ''))}
                  aria-invalid={codeError ? true : undefined}
                  aria-describedby={codeError ? codeErrId : undefined}
                  onKeyDown={(e) => {
                    if (e.key === 'Enter' && savedAcknowledged && !mfa.busy)
                      void handleConfirmSetup()
                  }}
                  className="border-border bg-input-background text-foreground focus-visible:ring-ring w-40 rounded-md border px-3 py-2 text-center font-mono text-lg tracking-[0.3em] focus-visible:ring-2 focus-visible:outline-none"
                />
                <FieldError id={codeErrId} message={codeError} />
              </div>
            </li>
          </ol>

          <div className="flex items-center justify-end gap-3">
            <button
              type="button"
              onClick={resetSetup}
              className="text-muted-foreground hover:text-foreground rounded-md px-3 py-2 text-sm transition-colors"
            >
              Cancel
            </button>
            <button
              type="button"
              onClick={() => void handleConfirmSetup()}
              disabled={mfa.busy || !savedAcknowledged || verifyCode.length !== 6}
              className="bg-brand text-brand-foreground inline-flex items-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50"
            >
              {mfa.busy ? (
                <Loader2 size={16} className="animate-spin" aria-hidden="true" />
              ) : (
                <Check size={16} aria-hidden="true" />
              )}
              Verify &amp; enable
            </button>
          </div>
        </div>
      )}
    </SecurityCard>
  )
}
