/**
 * Centralized Authentication Service
 * Handles all authentication flows with consistent AAL checking and MFA verification
 */

import { supabase } from '@/integrations/supabase/client';
import type { Session } from '@supabase/supabase-js';
import type { 
  AALLevel, 
  MFAFactor, 
  CheckAalResult, 
  AuthServiceResponse,
  MFAChallengeResult 
} from '@/types/auth';
import { setStepUpRequired, setAuthMethod, clearAllAuthFlags } from './sessionFlags';
import { logger } from './logger';
import { getErrorMessage } from './errorHandler';

/**
 * Extract AAL level from session using Supabase API
 * Always returns ground truth from server, not cached session data
 */
export async function getSessionAal(session: Session | null): Promise<AALLevel> {
  if (!session) {
    logger.log('[AuthService] No session, returning aal1');
    return 'aal1';
  }
  
  try {
    const { data, error } = await supabase.auth.mfa.getAuthenticatorAssuranceLevel();
    
    logger.log('[AuthService] getSessionAal result', { 
      hasData: !!data, 
      currentLevel: data?.currentLevel,
      nextLevel: data?.nextLevel,
      error: error?.message 
    });
    
    if (error) {
      logger.error('[AuthService] Error getting AAL', {
        action: 'get_session_aal',
        error: error.message
      });
      return 'aal1';
    }
    
    const level = (data.currentLevel as AALLevel) || 'aal1';
    logger.log('[AuthService] Returning AAL', { level });
    return level;
  } catch (error: unknown) {
    const errorMessage = getErrorMessage(error);
    logger.error('[AuthService] Exception getting AAL', {
      action: 'get_session_aal',
      error: errorMessage
    });
    return 'aal1';
  }
}

/**
 * Get enrolled MFA factors for the current user
 */
export async function getEnrolledFactors(): Promise<MFAFactor[]> {
  try {
    const { data, error } = await supabase.auth.mfa.listFactors();
    
    if (error) {
      logger.error('[AuthService] Error listing factors', {
        action: 'get_enrolled_factors',
        error: error.message
      });
      return [];
    }
    
    return (data?.totp || [])
      .filter(f => f.status === 'verified')
      .map(f => ({
        id: f.id,
        factor_type: 'totp' as const,
        status: 'verified' as const,
        friendly_name: f.friendly_name,
        created_at: f.created_at,
        updated_at: f.updated_at,
      }));
  } catch (error: unknown) {
    const errorMessage = getErrorMessage(error);
    logger.error('[AuthService] Exception listing factors', {
      action: 'get_enrolled_factors',
      error: errorMessage
    });
    return [];
  }
}

/**
 * Check if user needs AAL step-up
 * Returns detailed information about enrollment and current AAL level
 */
export async function checkAalStepUp(session: Session | null): Promise<CheckAalResult> {
  if (!session?.user) {
    return {
      needsStepUp: false,
      hasMfaEnrolled: false,
      currentLevel: 'aal1',
      hasEnrolledFactors: false,
    };
  }
  
  const [currentLevel, factors] = await Promise.all([
    getSessionAal(session),
    getEnrolledFactors(),
  ]);
  
  const hasEnrolledFactors = factors.length > 0;
  const needsStepUp = hasEnrolledFactors && currentLevel === 'aal1';
  
  return {
    needsStepUp,
    hasMfaEnrolled: hasEnrolledFactors,
    currentLevel,
    hasEnrolledFactors,
    factorId: factors[0]?.id,
  };
}

/**
 * Verify MFA is required for a user based on their role
 */
export async function verifyMfaRequired(userId: string): Promise<boolean> {
  try {
    const { data, error } = await supabase
      .from('user_roles')
      .select('role')
      .eq('user_id', userId)
      .in('role', ['admin', 'moderator']);
    
    if (error) {
      logger.error('[AuthService] Error checking roles', {
        action: 'verify_mfa_required',
        userId,
        error: error.message
      });
      return false;
    }
    
    return (data?.length || 0) > 0;
  } catch (error: unknown) {
    const errorMessage = getErrorMessage(error);
    logger.error('[AuthService] Exception checking roles', {
      action: 'verify_mfa_required',
      userId,
      error: errorMessage
    });
    return false;
  }
}

/**
 * Handle post-authentication flow for all auth methods
 * Detects if MFA step-up is needed and redirects accordingly
 */
export async function handlePostAuthFlow(
  session: Session,
  authMethod: 'password' | 'oauth' | 'magiclink'
): Promise<AuthServiceResponse<{ shouldRedirect: boolean; redirectTo?: string }>> {
  try {
    // Store auth method for audit logging
    setAuthMethod(authMethod);
    
    // Check if step-up is needed
    const aalCheck = await checkAalStepUp(session);
    
    if (aalCheck.needsStepUp) {
      logger.info('[AuthService] MFA step-up required', {
        authMethod,
        currentAal: aalCheck.currentLevel
      });
      
      // Set flag and redirect to step-up page
      setStepUpRequired(true, window.location.pathname);
      
      // Log audit event
      await logAuthEvent(session.user.id, 'mfa_step_up_required', {
        auth_method: authMethod,
        current_aal: aalCheck.currentLevel,
      });
      
      return {
        success: true,
        data: {
          shouldRedirect: true,
          redirectTo: '/auth/mfa-step-up',
        },
      };
    }
    
    // Log successful authentication
    await logAuthEvent(session.user.id, 'authentication_success', {
      auth_method: authMethod,
      aal: aalCheck.currentLevel,
    });
    
    return {
      success: true,
      data: {
        shouldRedirect: false,
      },
    };
  } catch (error: unknown) {
    const errorMessage = getErrorMessage(error);
    logger.error('[AuthService] Error in post-auth flow', {
      action: 'handle_post_auth_flow',
      authMethod,
      error: errorMessage
    });
    return {
      success: false,
      error: errorMessage,
    };
  }
}

/**
 * Verify MFA challenge was successful and session upgraded to AAL2
 */
export async function verifyMfaUpgrade(session: Session | null): Promise<MFAChallengeResult> {
  if (!session) {
    return {
      success: false,
      error: 'No session found',
    };
  }
  
  const currentAal = await getSessionAal(session);
  
  if (currentAal !== 'aal2') {
    logger.error('[AuthService] MFA verification failed', {
      action: 'verify_mfa_upgrade',
      expectedAal: 'aal2',
      actualAal: currentAal
    });
    await logAuthEvent(session.user.id, 'mfa_verification_failed', {
      expected_aal: 'aal2',
      actual_aal: currentAal,
    });
    
    return {
      success: false,
      error: 'Failed to upgrade session to AAL2',
      newAal: currentAal,
    };
  }
  
  // Log successful upgrade
  await logAuthEvent(session.user.id, 'mfa_verification_success', {
    new_aal: currentAal,
  });
  
  // Clear auth flags
  clearAllAuthFlags();
  
  return {
    success: true,
    newAal: currentAal,
  };
}

/**
 * Log authentication event to audit log
 */
async function logAuthEvent(
  userId: string,
  action: string,
  details: Record<string, any>
): Promise<void> {
  try {
    const { error } = await supabase.rpc('log_admin_action', {
      _admin_user_id: userId,
      _action: action,
      _target_user_id: userId,
      _details: details,
    });
    
    if (error) {
      logger.error('[AuthService] Error logging auth event', {
        action: 'log_auth_event',
        eventAction: action,
        userId,
        error: error.message
      });
    }
  } catch (error: unknown) {
    const errorMessage = getErrorMessage(error);
    logger.error('[AuthService] Exception logging auth event', {
      action: 'log_auth_event',
      eventAction: action,
      userId,
      error: errorMessage
    });
  }
}

/**
 * Handle sign out with proper cleanup
 */
export async function signOutUser(): Promise<AuthServiceResponse> {
  try {
    const { error } = await supabase.auth.signOut();
    
    if (error) {
      return {
        success: false,
        error: error.message,
      };
    }
    
    // Clear all session flags
    clearAllAuthFlags();
    
    return { success: true };
  } catch (error: unknown) {
    return {
      success: false,
      error: error instanceof Error ? error.message : 'Unknown error',
    };
  }
}
