/**
 * Authentication & Authorization Test Suite
 * 
 * Tests auth flows, MFA enforcement, role checks, and session management.
 */

import { supabase } from '@/integrations/supabase/client';
import type { TestSuite, TestResult } from '../testRunner';

export const authTestSuite: TestSuite = {
  id: 'auth',
  name: 'Authentication & Authorization',
  description: 'Tests for auth flows, MFA, roles, and permissions',
  tests: [
    {
      id: 'auth-001',
      name: 'User Session Validation',
      description: 'Validates current user session is valid with proper JWT structure',
      run: async (): Promise<TestResult> => {
        const startTime = Date.now();
        
        try {
          // Get current session
          const { data: { session }, error } = await supabase.auth.getSession();
          
          if (error) throw new Error(`Session fetch failed: ${error.message}`);
          if (!session) throw new Error('No active session found');
          if (!session.access_token) throw new Error('No access token in session');
          if (!session.user) throw new Error('No user in session');
          if (!session.user.id) throw new Error('No user ID in session');
          
          // Validate token structure (JWT has 3 parts separated by dots)
          const tokenParts = session.access_token.split('.');
          if (tokenParts.length !== 3) {
            throw new Error(`Invalid JWT structure: expected 3 parts, got ${tokenParts.length}`);
          }
          
          // Check expiration
          if (session.expires_at && session.expires_at < Date.now() / 1000) {
            throw new Error('Session token is expired');
          }
          
          const duration = Date.now() - startTime;
          
          return {
            id: 'auth-001',
            name: 'User Session Validation',
            suite: 'Authentication & Authorization',
            status: 'pass',
            duration,
            timestamp: new Date().toISOString(),
            details: {
              userId: session.user.id,
              email: session.user.email,
              expiresAt: session.expires_at,
              aal: (session.user as any).aal || 'aal1'
            }
          };
        } catch (error) {
          const duration = Date.now() - startTime;
          return {
            id: 'auth-001',
            name: 'User Session Validation',
            suite: 'Authentication & Authorization',
            status: 'fail',
            duration,
            error: error instanceof Error ? error.message : String(error),
            stack: error instanceof Error ? error.stack : undefined,
            timestamp: new Date().toISOString()
          };
        }
      }
    },
    {
      id: 'auth-002',
      name: 'Role-Based Access Control (RBAC)',
      description: 'Tests role checks are consistent across hooks and database functions',
      run: async (): Promise<TestResult> => {
        const startTime = Date.now();
        
        try {
          const { data: { user } } = await supabase.auth.getUser();
          if (!user) throw new Error('No authenticated user');
          
          // Query user_roles table
          const { data: roles, error: rolesError } = await supabase
            .from('user_roles')
            .select('role')
            .eq('user_id', user.id);
          
          if (rolesError) throw new Error(`Failed to fetch roles: ${rolesError.message}`);
          
          // Test is_moderator() database function
          const { data: isMod, error: modError } = await supabase
            .rpc('is_moderator', { _user_id: user.id });
          
          if (modError) throw new Error(`is_moderator() failed: ${modError.message}`);
          
          // Test is_superuser() database function
          const { data: isSuper, error: superError } = await supabase
            .rpc('is_superuser', { _user_id: user.id });
          
          if (superError) throw new Error(`is_superuser() failed: ${superError.message}`);
          
          // Validate consistency
          const hasModRole = roles?.some(r => ['moderator', 'admin', 'superuser'].includes(r.role));
          if (hasModRole !== isMod) {
            throw new Error(`Inconsistent moderator check: has role=${hasModRole}, is_moderator()=${isMod}`);
          }
          
          const hasSuperRole = roles?.some(r => r.role === 'superuser');
          if (hasSuperRole !== isSuper) {
            throw new Error(`Inconsistent superuser check: has role=${hasSuperRole}, is_superuser()=${isSuper}`);
          }
          
          const duration = Date.now() - startTime;
          
          return {
            id: 'auth-002',
            name: 'Role-Based Access Control (RBAC)',
            suite: 'Authentication & Authorization',
            status: 'pass',
            duration,
            timestamp: new Date().toISOString(),
            details: {
              roles: roles?.map(r => r.role) || [],
              isModerator: isMod,
              isSuperuser: isSuper,
              consistent: true
            }
          };
        } catch (error) {
          const duration = Date.now() - startTime;
          return {
            id: 'auth-002',
            name: 'Role-Based Access Control (RBAC)',
            suite: 'Authentication & Authorization',
            status: 'fail',
            duration,
            error: error instanceof Error ? error.message : String(error),
            stack: error instanceof Error ? error.stack : undefined,
            timestamp: new Date().toISOString()
          };
        }
      }
    },
    {
      id: 'auth-003',
      name: 'MFA Factor Detection',
      description: 'Tests MFA enrollment detection and AAL level',
      run: async (): Promise<TestResult> => {
        const startTime = Date.now();
        
        try {
          const { data: { user } } = await supabase.auth.getUser();
          if (!user) throw new Error('No authenticated user');
          
          // Get MFA factors
          const { data: factors, error: factorsError } = await supabase.auth.mfa.listFactors();
          
          if (factorsError) throw new Error(`Failed to list MFA factors: ${factorsError.message}`);
          
          const hasVerifiedFactor = factors?.totp?.some(f => f.status === 'verified') || false;
          const currentAAL = (user as any).aal || 'aal1';
          
          const duration = Date.now() - startTime;
          
          return {
            id: 'auth-003',
            name: 'MFA Factor Detection',
            suite: 'Authentication & Authorization',
            status: 'pass',
            duration,
            timestamp: new Date().toISOString(),
            details: {
              hasVerifiedMFA: hasVerifiedFactor,
              currentAAL: currentAAL,
              totpFactorCount: factors?.totp?.length || 0,
              verifiedFactorCount: factors?.totp?.filter(f => f.status === 'verified').length || 0
            }
          };
        } catch (error) {
          const duration = Date.now() - startTime;
          return {
            id: 'auth-003',
            name: 'MFA Factor Detection',
            suite: 'Authentication & Authorization',
            status: 'fail',
            duration,
            error: error instanceof Error ? error.message : String(error),
            stack: error instanceof Error ? error.stack : undefined,
            timestamp: new Date().toISOString()
          };
        }
      }
    },
    {
      id: 'auth-004',
      name: 'Banned User Detection',
      description: 'Tests banned user detection in profiles table',
      run: async (): Promise<TestResult> => {
        const startTime = Date.now();
        
        try {
          const { data: { user } } = await supabase.auth.getUser();
          if (!user) throw new Error('No authenticated user');
          
          // Query profile banned status
          const { data: profile, error: profileError } = await supabase
            .from('profiles')
            .select('banned')
            .eq('user_id', user.id)
            .single();
          
          if (profileError) throw new Error(`Failed to fetch profile: ${profileError.message}`);
          if (!profile) throw new Error('No profile found');
          
          // Test is_user_banned() database function
          const { data: isBanned, error: bannedError } = await supabase
            .rpc('is_user_banned', { _user_id: user.id });
          
          if (bannedError) throw new Error(`is_user_banned() failed: ${bannedError.message}`);
          
          // Validate consistency
          if (profile.banned !== isBanned) {
            throw new Error(`Inconsistent banned check: profile=${profile.banned}, is_user_banned()=${isBanned}`);
          }
          
          const duration = Date.now() - startTime;
          
          return {
            id: 'auth-004',
            name: 'Banned User Detection',
            suite: 'Authentication & Authorization',
            status: 'pass',
            duration,
            timestamp: new Date().toISOString(),
            details: {
              isBanned: profile.banned,
              consistent: true
            }
          };
        } catch (error) {
          const duration = Date.now() - startTime;
          return {
            id: 'auth-004',
            name: 'Banned User Detection',
            suite: 'Authentication & Authorization',
            status: 'fail',
            duration,
            error: error instanceof Error ? error.message : String(error),
            stack: error instanceof Error ? error.stack : undefined,
            timestamp: new Date().toISOString()
          };
        }
      }
    }
  ]
};
