'use client';

import { useCallback, useState } from 'react';

import { useCfgRouter } from './useCfgRouter';

import { apiAccounts, apiTotp } from '../../clients';
import { Analytics, AnalyticsCategory, AnalyticsEvent } from '../utils/analytics';
import { authLogger } from '../utils/logger';

export interface UseTwoFactorOptions {
  /** Callback on successful 2FA verification */
  onSuccess?: (user: any) => void;
  /** Callback on error */
  onError?: (error: string) => void;
  /** URL to redirect after successful verification */
  redirectUrl?: string;
  /** Skip automatic redirect after success (caller handles navigation) */
  skipRedirect?: boolean;
}

export interface UseTwoFactorReturn {
  /** Loading state */
  isLoading: boolean;
  /** Error message */
  error: string | null;
  /** Warning message (e.g., low backup codes) */
  warning: string | null;
  /** Remaining backup codes (if backup code was used) */
  remainingBackupCodes: number | null;
  /** Verify TOTP code */
  verifyTOTP: (sessionId: string, code: string) => Promise<boolean>;
  /** Verify backup code */
  verifyBackupCode: (sessionId: string, backupCode: string) => Promise<boolean>;
  /** Clear error */
  clearError: () => void;
}

/**
 * Hook for 2FA verification during login.
 *
 * Usage:
 * 1. After OTP/OAuth verification returns requires_2fa=true and session_id
 * 2. Show 2FA form and collect TOTP code from user
 * 3. Call verifyTOTP(sessionId, code) to complete authentication
 *
 * @example
 * ```tsx
 * const { isLoading, error, verifyTOTP, verifyBackupCode } = useTwoFactor({
 *   onSuccess: (user) => console.log('Logged in:', user),
 *   onError: (error) => console.error(error),
 *   redirectUrl: '/dashboard',
 * });
 *
 * const handleSubmit = async (code: string) => {
 *   if (useBackupCode) {
 *     await verifyBackupCode(sessionId, code);
 *   } else {
 *     await verifyTOTP(sessionId, code);
 *   }
 * };
 * ```
 */
export const useTwoFactor = (options: UseTwoFactorOptions = {}): UseTwoFactorReturn => {
  const { onSuccess, onError, redirectUrl, skipRedirect = false } = options;
  const router = useCfgRouter();

  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [warning, setWarning] = useState<string | null>(null);
  const [remainingBackupCodes, setRemainingBackupCodes] = useState<number | null>(null);

  const clearError = useCallback(() => {
    setError(null);
  }, []);

  /**
   * Handle successful 2FA verification
   */
  const handleSuccess = useCallback((response: {
    access_token: string;
    refresh_token: string;
    user: any;
    warning?: string;
    remaining_backup_codes?: number;
  }) => {
    // Save tokens
    apiAccounts.setToken(response.access_token, response.refresh_token);

    // Set warning if any
    if (response.warning) {
      setWarning(response.warning);
    }

    // Set remaining backup codes if provided
    if (response.remaining_backup_codes !== undefined) {
      setRemainingBackupCodes(response.remaining_backup_codes);
    }

    // Track successful 2FA
    Analytics.event(AnalyticsEvent.AUTH_LOGIN_SUCCESS, {
      category: AnalyticsCategory.AUTH,
      label: '2fa',
    });

    // Set user ID for tracking
    if (response.user?.id) {
      Analytics.setUser(String(response.user.id));
    }

    // Call success callback
    onSuccess?.(response.user);

    // Redirect (unless skipRedirect is true)
    if (!skipRedirect) {
      const finalRedirectUrl = redirectUrl || '/dashboard';
      authLogger.info('2FA successful, redirecting to:', finalRedirectUrl);
      router.hardPush(finalRedirectUrl);
    }
  }, [onSuccess, redirectUrl, router, skipRedirect]);

  /**
   * Verify TOTP code from authenticator app
   */
  const verifyTOTP = useCallback(async (sessionId: string, code: string): Promise<boolean> => {
    if (!sessionId) {
      const msg = 'Missing 2FA session ID';
      setError(msg);
      onError?.(msg);
      return false;
    }

    if (!code || code.length !== 6) {
      const msg = 'Please enter a 6-digit code';
      setError(msg);
      onError?.(msg);
      return false;
    }

    setIsLoading(true);
    setError(null);

    try {
      authLogger.info('Verifying TOTP code...');

      const response = await apiTotp.totp_verification.totpVerifyCreate({
        session_id: sessionId,
        code,
      });

      if (!response.access_token || !response.refresh_token) {
        throw new Error('Invalid response from 2FA verification');
      }

      handleSuccess(response);
      return true;

    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : 'Invalid verification code';
      authLogger.error('2FA TOTP verification error:', err);
      setError(errorMessage);
      onError?.(errorMessage);

      // Track failed 2FA
      Analytics.event(AnalyticsEvent.AUTH_OTP_VERIFY_FAIL, {
        category: AnalyticsCategory.AUTH,
        label: '2fa-totp',
      });

      return false;
    } finally {
      setIsLoading(false);
    }
  }, [handleSuccess, onError]);

  /**
   * Verify backup recovery code
   */
  const verifyBackupCode = useCallback(async (sessionId: string, backupCode: string): Promise<boolean> => {
    if (!sessionId) {
      const msg = 'Missing 2FA session ID';
      setError(msg);
      onError?.(msg);
      return false;
    }

    if (!backupCode || backupCode.length < 8) {
      const msg = 'Please enter your backup code';
      setError(msg);
      onError?.(msg);
      return false;
    }

    setIsLoading(true);
    setError(null);

    try {
      authLogger.info('Verifying backup code...');

      const response = await apiTotp.totp_verification.totpVerifyBackupCreate({
        session_id: sessionId,
        backup_code: backupCode.replace(/\s+/g, ''), // Remove spaces
      });

      if (!response.access_token || !response.refresh_token) {
        throw new Error('Invalid response from backup code verification');
      }

      handleSuccess(response);
      return true;

    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : 'Invalid backup code';
      authLogger.error('2FA backup code verification error:', err);
      setError(errorMessage);
      onError?.(errorMessage);

      // Track failed 2FA
      Analytics.event(AnalyticsEvent.AUTH_OTP_VERIFY_FAIL, {
        category: AnalyticsCategory.AUTH,
        label: '2fa-backup',
      });

      return false;
    } finally {
      setIsLoading(false);
    }
  }, [handleSuccess, onError]);

  return {
    isLoading,
    error,
    warning,
    remainingBackupCodes,
    verifyTOTP,
    verifyBackupCode,
    clearError,
  };
};
