"use client"

import { useCallback, useEffect, useRef } from 'react';

import { useAuth } from '../context';
import type { AuthChannel, AuthFormReturn, UseAuthFormOptions } from '../types';
import { authLogger } from '../utils/logger';
import { useAuthFormState } from './useAuthFormState';
import { useAuthValidation } from './useAuthValidation';
import { useAutoAuth } from './useAutoAuth';
import { useTwoFactor } from './useTwoFactor';

/**
 * Complete auth form hook.
 * Composes smaller hooks for state, validation, and submission.
 */
export const useAuthForm = (options: UseAuthFormOptions): AuthFormReturn => {
  const {
    onIdentifierSuccess,
    onOTPSuccess,
    onError,
    sourceUrl,
    redirectUrl,
    requireTermsAcceptance = false,
    authPath = '/auth',
    enable2FASetup = true,
  } = options;

  // Compose smaller hooks
  const formState = useAuthFormState();
  const validation = useAuthValidation();

  // Ref to track auto-submit from URL
  const isAutoSubmitFromUrlRef = useRef(false);

  // Auth context for API calls and storage
  const {
    requestOTP,
    verifyOTP,
    getSavedEmail,
    saveEmail,
    clearSavedEmail,
    getSavedPhone,
    savePhone,
    clearSavedPhone,
  } = useAuth();

  // Destructure for convenience
  const {
    identifier,
    channel,
    otp,
    isLoading,
    acceptedTerms,
    twoFactorSessionId,
    twoFactorCode,
    useBackupCode,
    setIdentifier,
    setChannel,
    setOtp,
    setStep,
    setError,
    setIsLoading,
    clearError,
    setTwoFactorSessionId,
    setShouldPrompt2FA,
    setTwoFactorCode,
    setUseBackupCode,
  } = formState;

  // 2FA verification hook - skip redirect so we can show success screen
  const twoFactor = useTwoFactor({
    onSuccess: () => {
      authLogger.info('2FA verification successful, showing success screen');
      setStep('success');
      onOTPSuccess?.();
    },
    onError: (error) => {
      setError(error);
      onError?.(error);
    },
    redirectUrl,
    skipRedirect: true, // We handle navigation via success step
  });

  const { detectChannelFromIdentifier, validateIdentifier } = validation;

  // ─────────────────────────────────────────────────────────────────────────
  // Storage Helper
  // ─────────────────────────────────────────────────────────────────────────

  const saveIdentifierToStorage = useCallback((id: string, ch: AuthChannel) => {
    if (ch === 'email') {
      saveEmail(id);
      clearSavedPhone();
    } else {
      savePhone(id);
      clearSavedEmail();
    }
  }, [saveEmail, savePhone, clearSavedEmail, clearSavedPhone]);

  // ─────────────────────────────────────────────────────────────────────────
  // Effects
  // ─────────────────────────────────────────────────────────────────────────

  // Load saved identifier on mount
  useEffect(() => {
    const savedPhone = getSavedPhone();
    const savedEmail = getSavedEmail();

    // Prioritize phone over email
    if (savedPhone) {
      setIdentifier(savedPhone);
      setChannel('phone');
    } else if (savedEmail) {
      setIdentifier(savedEmail);
      setChannel('email');
    }
  }, [getSavedEmail, getSavedPhone, setIdentifier, setChannel]);

  // Auto-detect channel when identifier changes
  useEffect(() => {
    if (identifier) {
      const detected = detectChannelFromIdentifier(identifier);
      if (detected && detected !== channel) {
        setChannel(detected);
      }
    }
  }, [identifier, channel, detectChannelFromIdentifier, setChannel]);

  // ─────────────────────────────────────────────────────────────────────────
  // Submit Handlers
  // ─────────────────────────────────────────────────────────────────────────

  const handleIdentifierSubmit = useCallback(async (e: React.FormEvent) => {
    e.preventDefault();

    if (!identifier) {
      const msg = channel === 'phone'
        ? 'Please enter your phone number'
        : 'Please enter your email address';
      setError(msg);
      onError?.(msg);
      return;
    }

    if (!validateIdentifier(identifier, channel)) {
      const msg = channel === 'phone'
        ? 'Please enter a valid phone number (e.g., +1234567890)'
        : 'Please enter a valid email address';
      setError(msg);
      onError?.(msg);
      return;
    }

    if (requireTermsAcceptance && !acceptedTerms) {
      const msg = 'Please accept the Terms of Service and Privacy Policy';
      setError(msg);
      onError?.(msg);
      return;
    }

    setIsLoading(true);
    clearError();

    try {
      const result = await requestOTP(identifier, channel, sourceUrl);

      if (result.success) {
        saveIdentifierToStorage(identifier, channel);
        setStep('otp');
        onIdentifierSuccess?.(identifier, channel);
      } else {
        setError(result.message);
        onError?.(result.message);
      }
    } catch {
      const msg = 'An unexpected error occurred';
      setError(msg);
      onError?.(msg);
    } finally {
      setIsLoading(false);
    }
  }, [
    identifier, channel, acceptedTerms, requireTermsAcceptance,
    validateIdentifier, requestOTP, saveIdentifierToStorage,
    setError, setIsLoading, setStep, clearError,
    onIdentifierSuccess, onError, sourceUrl,
  ]);

  // Core OTP submit - accepts explicit values to avoid stale closures
  const submitOTP = useCallback(async (
    submitIdentifier: string,
    submitOtp: string,
    submitChannel: AuthChannel
  ): Promise<boolean> => {
    if (!submitOtp || submitOtp.length < 6) {
      const msg = 'Please enter the 6-digit verification code';
      setError(msg);
      onError?.(msg);
      return false;
    }

    setIsLoading(true);
    clearError();

    try {
      // Skip redirect - we'll show success screen first
      const result = await verifyOTP(submitIdentifier, submitOtp, submitChannel, sourceUrl, redirectUrl, true);

      // Check if 2FA is required (user has TOTP device)
      if (result.requires_2fa && result.session_id) {
        authLogger.info('2FA required after OTP verification');
        setTwoFactorSessionId(result.session_id);
        setShouldPrompt2FA(result.should_prompt_2fa || false);
        setStep('2fa');
        saveIdentifierToStorage(submitIdentifier, submitChannel);
        return true; // OTP was successful, now need 2FA
      }

      if (result.success) {
        saveIdentifierToStorage(submitIdentifier, submitChannel);

        // Check if user should be prompted to set up 2FA
        // Only show 2FA setup prompt if enable2FASetup is true (default)
        if (result.should_prompt_2fa && enable2FASetup) {
          authLogger.info('OTP verification successful, prompting 2FA setup');
          setShouldPrompt2FA(true);
          setStep('2fa-setup');
          onOTPSuccess?.();
          return true;
        }

        // Skip 2FA setup prompt if enable2FASetup is false
        if (result.should_prompt_2fa && !enable2FASetup) {
          authLogger.info('OTP verification successful, skipping 2FA setup prompt (disabled)');
        } else {
          authLogger.info('OTP verification successful, showing success screen');
        }
        setStep('success');
        onOTPSuccess?.();
        return true;
      } else {
        setError(result.message);
        onError?.(result.message);
        return false;
      }
    } catch {
      const msg = 'An unexpected error occurred';
      setError(msg);
      onError?.(msg);
      return false;
    } finally {
      setIsLoading(false);
    }
  }, [verifyOTP, saveIdentifierToStorage, setError, setIsLoading, clearError, onOTPSuccess, onError, sourceUrl, redirectUrl, setTwoFactorSessionId, setShouldPrompt2FA, setStep, enable2FASetup]);

  const handleOTPSubmit = useCallback(async (e: React.FormEvent) => {
    e.preventDefault();
    await submitOTP(identifier, otp, channel);
  }, [identifier, otp, channel, submitOTP]);

  const handleResendOTP = useCallback(async () => {
    setIsLoading(true);
    clearError();

    try {
      const result = await requestOTP(identifier, channel, sourceUrl);

      if (result.success) {
        saveIdentifierToStorage(identifier, channel);
        setOtp('');
      } else {
        setError(result.message);
        onError?.(result.message);
      }
    } catch {
      const msg = 'Failed to resend verification code';
      setError(msg);
      onError?.(msg);
    } finally {
      setIsLoading(false);
    }
  }, [identifier, channel, requestOTP, saveIdentifierToStorage, setOtp, setError, setIsLoading, clearError, onError, sourceUrl]);

  const handleBackToIdentifier = useCallback(() => {
    setStep('identifier');
    clearError();
  }, [setStep, clearError]);

  const forceOTPStep = useCallback(() => {
    setStep('otp');
    clearError();
  }, [setStep, clearError]);

  // ─────────────────────────────────────────────────────────────────────────
  // 2FA Handlers
  // ─────────────────────────────────────────────────────────────────────────

  const handle2FASubmit = useCallback(async (e: React.FormEvent) => {
    e.preventDefault();

    if (!twoFactorSessionId) {
      const msg = 'Missing 2FA session';
      setError(msg);
      onError?.(msg);
      return;
    }

    if (useBackupCode) {
      await twoFactor.verifyBackupCode(twoFactorSessionId, twoFactorCode);
    } else {
      await twoFactor.verifyTOTP(twoFactorSessionId, twoFactorCode);
    }
  }, [twoFactorSessionId, twoFactorCode, useBackupCode, twoFactor, setError, onError]);

  const handleUseBackupCode = useCallback(() => {
    setUseBackupCode(true);
    setTwoFactorCode('');
    clearError();
  }, [setUseBackupCode, setTwoFactorCode, clearError]);

  const handleUseTOTP = useCallback(() => {
    setUseBackupCode(false);
    setTwoFactorCode('');
    clearError();
  }, [setUseBackupCode, setTwoFactorCode, clearError]);

  // ─────────────────────────────────────────────────────────────────────────
  // Auto-auth from URL
  // ─────────────────────────────────────────────────────────────────────────

  useAutoAuth({
    allowedPaths: [authPath],
    onOTPDetected: (detectedOtp: string) => {
      if (isAutoSubmitFromUrlRef.current || isLoading) return;
      isAutoSubmitFromUrlRef.current = true;

      authLogger.info('OTP detected from URL, auto-submitting');

      const savedPhone = getSavedPhone();
      const savedEmail = getSavedEmail();

      let autoIdentifier = '';
      let autoChannel: AuthChannel = 'email';

      if (savedPhone) {
        autoIdentifier = savedPhone;
        autoChannel = 'phone';
      } else if (savedEmail) {
        autoIdentifier = savedEmail;
        autoChannel = 'email';
      }

      if (!autoIdentifier) {
        authLogger.warn('No saved identifier found for auto-submit');
        isAutoSubmitFromUrlRef.current = false;
        return;
      }

      // Update UI state
      setIdentifier(autoIdentifier);
      setChannel(autoChannel);
      setOtp(detectedOtp);
      setStep('otp');

      // Submit with explicit values
      setTimeout(async () => {
        try {
          await submitOTP(autoIdentifier, detectedOtp, autoChannel);
        } finally {
          isAutoSubmitFromUrlRef.current = false;
        }
      }, 100);
    },
    cleanupUrl: true,
  });

  // ─────────────────────────────────────────────────────────────────────────
  // Return
  // ─────────────────────────────────────────────────────────────────────────

  return {
    // State
    ...formState,

    // Submit handlers
    handleIdentifierSubmit,
    handleOTPSubmit,
    handleResendOTP,
    handleBackToIdentifier,
    forceOTPStep,

    // 2FA handlers
    handle2FASubmit,
    handleUseBackupCode,
    handleUseTOTP,

    // Validation
    ...validation,

    // Auto-submit ref
    isAutoSubmittingFromUrl: isAutoSubmitFromUrlRef,

    // 2FA state from hook (for loading indicator)
    is2FALoading: twoFactor.isLoading,
    twoFactorWarning: twoFactor.warning,
  };
};

// Re-export types for convenience
export type { AuthFormReturn, UseAuthFormOptions } from '../types';
