'use client';

import { useEffect, useRef, useState } from 'react';
import {
  LoginOtpChallenge,
  resendLoginOtpAction,
  verifyLoginOtpAction,
} from '@/app/(auth)/actions';
import { AlertCircle } from 'lucide-react';
import { Alert, AlertIcon, AlertTitle } from '@/components/ui/alert';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Spinner } from '@/components/ui/spinners';

type Props = {
  challenge: LoginOtpChallenge;
  /** Called with the account once the code is accepted and the session cookies are set. */
  onVerified: (accountTypeId: number | undefined) => void;
  /** Back to email/password, e.g. after the attempt expired. */
  onBack: (message?: string) => void;
};

/** Second sign-in step: the 6-digit code emailed after a correct password. */
export default function OtpStep({ challenge, onVerified, onBack }: Props) {
  const [code, setCode] = useState('');
  const [error, setError] = useState<string | null>(null);
  const [notice, setNotice] = useState<string | null>(null);
  const [busy, setBusy] = useState(false);
  const [resending, setResending] = useState(false);
  const [wait, setWait] = useState(challenge.resend_in);
  const lastSubmitted = useRef<string | null>(null);

  useEffect(() => {
    if (wait <= 0) return;
    const id = setTimeout(() => setWait((s) => s - 1), 1000);
    return () => clearTimeout(id);
  }, [wait]);

  async function submit(value: string) {
    if (value.length !== 6 || busy || lastSubmitted.current === value) return;
    lastSubmitted.current = value;
    setBusy(true);
    setError(null);
    try {
      const result = await verifyLoginOtpAction(challenge.otp_token, value);
      if (result.status) {
        onVerified(result.data?.account_type_id);
        return;
      }
      // 410: expired, already used, or too many wrong codes — start over.
      if (result.httpStatus === 410) {
        onBack(result.message);
        return;
      }
      setError(result.message ?? 'The code is incorrect.');
      setCode('');
      lastSubmitted.current = null;
    } finally {
      setBusy(false);
    }
  }

  async function resend() {
    setResending(true);
    setError(null);
    try {
      const result = await resendLoginOtpAction(challenge.otp_token);
      if (result.status) {
        setNotice(result.message ?? 'We sent you a new code.');
        setWait(result.resendIn ?? 60);
        setCode('');
        lastSubmitted.current = null;
      } else if (result.httpStatus === 410) {
        onBack(result.message);
      } else {
        setError(result.message ?? 'Could not send a new code. Please try again.');
      }
    } finally {
      setResending(false);
    }
  }

  return (
    <form
      className="block w-full space-y-5"
      onSubmit={(e) => {
        e.preventDefault();
        lastSubmitted.current = null;
        void submit(code);
      }}
    >
      <div className="space-y-1.5 pb-3 text-center">
        <h1 className="text-2xl font-semibold tracking-tight">Check your email</h1>
        <p className="text-sm text-muted-foreground">
          We sent a 6-digit sign-in code to <span className="font-medium text-foreground">{challenge.email}</span>.
        </p>
      </div>

      {error && (
        <Alert variant="destructive">
          <AlertIcon>
            <AlertCircle />
          </AlertIcon>
          <AlertTitle>{error}</AlertTitle>
        </Alert>
      )}
      {notice && !error && (
        <Alert>
          <AlertTitle>{notice}</AlertTitle>
        </Alert>
      )}

      <Input
        autoFocus
        inputMode="numeric"
        autoComplete="one-time-code"
        maxLength={6}
        placeholder="000000"
        className="text-center text-lg tracking-[0.5em]"
        value={code}
        disabled={busy}
        onChange={(e) => {
          const value = e.target.value.replace(/\D/g, '').slice(0, 6);
          setCode(value);
          if (value.length === 6) void submit(value);
        }}
      />

      <Button type="submit" className="w-full" disabled={busy || code.length !== 6}>
        {busy ? <Spinner className="size-4 animate-spin" /> : null}
        Verify
      </Button>

      <div className="flex items-center justify-between text-sm">
        <Button type="button" variant="ghost" size="sm" onClick={() => onBack()} disabled={busy}>
          Back to sign in
        </Button>
        <Button
          type="button"
          variant="ghost"
          size="sm"
          onClick={resend}
          disabled={wait > 0 || resending || busy}
        >
          {resending ? <Spinner className="size-4 animate-spin" /> : null}
          {wait > 0 ? `Send a new code in ${wait}s` : 'Send a new code'}
        </Button>
      </div>
    </form>
  );
}
