/**
 * VerificationStep - Enter 6-digit OTP code
 *
 * Features:
 * - Auto-submit on complete
 * - 60s resend cooldown with countdown
 * - Code expiry countdown timer
 * - Error display that works for repeated identical errors
 * - Max 3 resend attempts before forcing restart
 */

"use client";

import { useState, useEffect, useCallback } from "react";
import { Button } from "@/components/atoms";
import { OtpInput, OtpExpiryDisplay } from "@/components/molecules";
import { useGetStartedMachine } from "../../../hooks/useGetStartedMachine";

const RESEND_COOLDOWN_SECONDS = 60;
const MAX_RESENDS = 3;

function useResendCooldown() {
  const [countdown, setCountdown] = useState(RESEND_COOLDOWN_SECONDS);
  const [resendCount, setResendCount] = useState(0);

  // Re-run timer whenever resendCount changes (initial mount + each resend)
  useEffect(() => {
    if (countdown <= 0) return;

    const id = setInterval(() => {
      setCountdown(prev => {
        if (prev <= 1) {
          clearInterval(id);
          return 0;
        }
        return prev - 1;
      });
    }, 1000);

    return () => clearInterval(id);
  }, [resendCount]); // eslint-disable-line react-hooks/exhaustive-deps

  const triggerCooldown = useCallback(() => {
    setResendCount(prev => prev + 1);
    setCountdown(RESEND_COOLDOWN_SECONDS);
  }, []);

  return { countdown, triggerCooldown, maxedOut: resendCount >= MAX_RESENDS };
}

function useExpiryTimer(codeExpiresAt: string | null) {
  const [timeRemaining, setTimeRemaining] = useState<number | null>(null);

  useEffect(() => {
    if (!codeExpiresAt) return;

    const expiryTime = new Date(codeExpiresAt).getTime();
    if (Number.isNaN(expiryTime)) {
      setTimeRemaining(0);
      return;
    }

    const update = () => {
      const remaining = Math.max(0, Math.floor((expiryTime - Date.now()) / 1000));
      setTimeRemaining(remaining);
    };

    update();
    const interval = setInterval(update, 1000);
    return () => clearInterval(interval);
  }, [codeExpiresAt]);

  const isExpired = timeRemaining !== null && timeRemaining <= 0;
  return { timeRemaining, isExpired };
}

function ResendButton({
  disabled,
  maxedOut,
  countdown,
  onClick,
}: {
  disabled: boolean;
  maxedOut: boolean;
  countdown: number;
  onClick: () => void;
}) {
  let label = "Resend code";
  if (maxedOut) label = "Max resends reached";
  else if (countdown > 0) label = `Resend in ${countdown}s`;

  return (
    <Button
      type="button"
      variant="ghost"
      onClick={onClick}
      disabled={disabled || maxedOut}
      className="text-sm"
    >
      {label}
    </Button>
  );
}

export function VerificationStep() {
  const { state, send } = useGetStartedMachine();

  const loading = state.matches({ verification: "loading" });
  const machineError = state.context.error;
  const machineErrorId = state.context.errorId;
  const attemptsRemaining = state.context.attemptsRemaining;
  const email = state.context.formData.email;
  const codeExpiresAt = state.context.codeExpiresAt;

  const [code, setCode] = useState("");
  const [localError, setLocalError] = useState<string | null>(null);

  const { countdown, triggerCooldown, maxedOut } = useResendCooldown();
  const { timeRemaining, isExpired } = useExpiryTimer(codeExpiresAt);

  const resendDisabled = countdown > 0 || loading;

  // Sync machine errors into local state using errorId to detect changes
  useEffect(() => {
    if (machineError && machineErrorId > 0) {
      setLocalError(machineError);
      setCode("");
    }
  }, [machineError, machineErrorId]);

  const handleCodeChange = useCallback((value: string) => {
    setCode(value);
    setLocalError(null);
  }, []);

  const handleComplete = useCallback(
    (completedCode: string) => {
      if (!loading && !isExpired) {
        setCode(completedCode);
        send({ type: "VERIFY_CODE", code: completedCode });
      }
    },
    [loading, isExpired, send]
  );

  const handleVerify = useCallback(() => {
    if (code.length === 6 && !isExpired) {
      send({ type: "VERIFY_CODE", code });
    }
  }, [code, isExpired, send]);

  const handleResend = useCallback(() => {
    if (resendDisabled || maxedOut) return;
    setCode("");
    setLocalError(null);
    triggerCooldown();
    send({ type: "SEND_CODE", email });
  }, [resendDisabled, maxedOut, email, send, triggerCooldown]);

  const handleGoBack = useCallback(() => {
    send({ type: "RESET" });
    send({ type: "START" });
  }, [send]);

  return (
    <div className="space-y-6">
      <div className="text-center space-y-2">
        <p className="text-sm text-muted-foreground">Enter the 6-digit code sent to</p>
        <p className="font-medium text-foreground">{email}</p>
      </div>

      <OtpInput
        value={code}
        onChange={handleCodeChange}
        onComplete={handleComplete}
        disabled={loading || isExpired}
        error={localError ?? undefined}
        autoFocus
      />

      {typeof attemptsRemaining === "number" && attemptsRemaining < 3 && (
        <p className="text-sm text-warning text-center">
          {attemptsRemaining} {attemptsRemaining === 1 ? "attempt" : "attempts"} remaining
        </p>
      )}

      <OtpExpiryDisplay timeRemaining={timeRemaining} isExpired={isExpired} />

      <div className="space-y-3">
        <Button
          type="button"
          onClick={handleVerify}
          disabled={loading || code.length !== 6 || isExpired}
          loading={loading}
          className="w-full h-11"
        >
          {loading ? "Verifying..." : "Verify Code"}
        </Button>

        <div className="flex items-center justify-between">
          <Button
            type="button"
            variant="ghost"
            onClick={handleGoBack}
            disabled={loading}
            className="text-sm"
          >
            Change email
          </Button>

          <ResendButton
            disabled={resendDisabled}
            maxedOut={maxedOut}
            countdown={countdown}
            onClick={handleResend}
          />
        </div>
      </div>
    </div>
  );
}
