'use client';

import { useState } from 'react';
import type { SupabaseClient } from '@supabase/supabase-js';
import {
  enrollPasskey,
  passkeyErrorMessage,
} from '@/lib/auth/webauthn-client';

/**
 * Remove any leftover *unverified* factors of a given type before starting a
 * fresh enrollment. GoTrue rejects a second enroll with a duplicate friendly
 * name, and abandoned/unverified factors would otherwise block re-enrollment
 * (e.g. after a refresh mid-flow). Unenrolling unverified factors does not
 * require aal2.
 */
async function cleanupUnverified(
  supabase: SupabaseClient,
  factorType: 'totp' | 'webauthn',
): Promise<void> {
  const { data } = await supabase.auth.mfa.listFactors();
  const stale =
    data?.all.filter(
      (f) => f.factor_type === factorType && f.status === 'unverified',
    ) ?? [];
  for (const f of stale) {
    await supabase.auth.mfa.unenroll({ factorId: f.id });
  }
}

/** TOTP authenticator-app enrollment: QR + manual secret, then code verify. */
export function TotpEnrollPanel({
  supabase,
  onVerified,
}: {
  supabase: SupabaseClient;
  onVerified: () => void;
}) {
  const [stage, setStage] = useState<'idle' | 'pending'>('idle');
  const [qr, setQr] = useState('');
  const [secret, setSecret] = useState('');
  const [factorId, setFactorId] = useState('');
  const [code, setCode] = useState('');
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);

  async function start() {
    setError(null);
    setBusy(true);
    try {
      await cleanupUnverified(supabase, 'totp');
      const { data, error } = await supabase.auth.mfa.enroll({
        factorType: 'totp',
        friendlyName: 'Authenticator app',
      });
      if (error) throw error;
      if (!data || !('totp' in data)) {
        throw new Error('Unexpected enrollment response.');
      }
      setFactorId(data.id);
      setQr(data.totp.qr_code);
      setSecret(data.totp.secret);
      setStage('pending');
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setBusy(false);
    }
  }

  async function verify(e: React.FormEvent) {
    e.preventDefault();
    setError(null);
    setBusy(true);
    try {
      const { data: ch, error: ce } = await supabase.auth.mfa.challenge({
        factorId,
      });
      if (ce) throw ce;
      const { error: ve } = await supabase.auth.mfa.verify({
        factorId,
        challengeId: ch.id,
        code: code.trim(),
      });
      if (ve) throw ve;
      onVerified();
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setBusy(false);
    }
  }

  if (stage === 'idle') {
    return (
      <div className="card">
        <h2>Authenticator app</h2>
        <p className="muted">
          Use an app like Google Authenticator, 1Password, or Authy to generate
          6-digit codes.
        </p>
        {error && <p className="error">{error}</p>}
        <button type="button" onClick={start} disabled={busy}>
          {busy ? 'Preparing…' : 'Set up authenticator app'}
        </button>
      </div>
    );
  }

  return (
    <div className="card">
      <h2>Scan the QR code</h2>
      <p className="muted">
        Scan this with your authenticator app, then enter the 6-digit code to
        confirm.
      </p>
      {qr && (
        // eslint-disable-next-line @next/next/no-img-element
        <img
          src={qr}
          alt="TOTP QR code"
          width={200}
          height={200}
          style={{ background: '#fff', padding: 8, borderRadius: 8 }}
        />
      )}
      <p className="muted" style={{ marginTop: '0.75rem' }}>
        Can&apos;t scan? Enter this secret manually:
      </p>
      <div className="token">{secret}</div>
      <form onSubmit={verify}>
        <label htmlFor="totp-code">6-digit code</label>
        <input
          id="totp-code"
          type="text"
          inputMode="numeric"
          autoComplete="one-time-code"
          pattern="[0-9]*"
          maxLength={6}
          required
          value={code}
          onChange={(e) => setCode(e.target.value)}
        />
        {error && <p className="error">{error}</p>}
        <div className="row" style={{ marginTop: '1rem' }}>
          <button type="submit" disabled={busy || code.trim().length < 6}>
            {busy ? 'Verifying…' : 'Verify and enable'}
          </button>
        </div>
      </form>
    </div>
  );
}

/** Passkey (WebAuthn) enrollment via the simplewebauthn ceremony. */
export function PasskeyEnrollPanel({
  supabase,
  onVerified,
}: {
  supabase: SupabaseClient;
  onVerified: () => void;
}) {
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);

  async function start() {
    setError(null);
    setBusy(true);
    try {
      await cleanupUnverified(supabase, 'webauthn');
      await enrollPasskey(supabase, 'Passkey');
      onVerified();
    } catch (e) {
      setError(passkeyErrorMessage(e));
    } finally {
      setBusy(false);
    }
  }

  return (
    <div className="card">
      <h2>Passkey</h2>
      <p className="muted">
        Use your device&apos;s biometrics, screen lock, or a hardware security
        key.
      </p>
      {error && <p className="error">{error}</p>}
      <button type="button" onClick={start} disabled={busy}>
        {busy ? 'Waiting for passkey…' : 'Set up a passkey'}
      </button>
    </div>
  );
}

/** One-time display of freshly generated recovery codes. */
export function RecoveryCodesPanel({ codes }: { codes: string[] }) {
  const [copied, setCopied] = useState(false);

  function copy() {
    navigator.clipboard
      .writeText(codes.join('\n'))
      .then(() => setCopied(true))
      .catch(() => setCopied(false));
  }

  return (
    <div className="card">
      <h2>Save your recovery codes</h2>
      <p className="muted">
        Store these somewhere safe. Each code can be used once to recover access
        if you lose your authenticator and passkeys. They will not be shown
        again.
      </p>
      <div
        className="token"
        style={{ display: 'grid', gap: '0.25rem', lineHeight: 1.8 }}
      >
        {codes.map((c) => (
          <span key={c}>{c}</span>
        ))}
      </div>
      <div className="row" style={{ marginTop: '1rem' }}>
        <button type="button" className="secondary" onClick={copy}>
          {copied ? 'Copied' : 'Copy codes'}
        </button>
      </div>
    </div>
  );
}
