// Security utilities embedded directly
const loginAttempts = new Map<string, { count: number; lastAttempt: number }>();
const blockedIPs = new Map<string, number>();

const checkRateLimit = (ip: string): { allowed: boolean; attemptsLeft: number } => {
  const now = Date.now();
  const maxAttempts = 5;
  const windowMs = 15 * 60 * 1000; // 15 minutes
  const blockDurationMs = 60 * 60 * 1000; // 1 hour

  const blockedUntil = blockedIPs.get(ip);
  if (blockedUntil && now < blockedUntil) {
    return { allowed: false, attemptsLeft: 0 };
  }

  if (blockedUntil && now >= blockedUntil) {
    blockedIPs.delete(ip);
  }

  const attempts = loginAttempts.get(ip);
  if (attempts && (now - attempts.lastAttempt) > windowMs) {
    loginAttempts.delete(ip);
    return { allowed: true, attemptsLeft: maxAttempts };
  }

  const currentCount = attempts?.count || 0;
  if (currentCount >= maxAttempts) {
    blockedIPs.set(ip, now + blockDurationMs);
    return { allowed: false, attemptsLeft: 0 };
  }

  return { allowed: true, attemptsLeft: maxAttempts - currentCount };
};

const recordFailedAttempt = (ip: string): void => {
  const now = Date.now();
  const attempts = loginAttempts.get(ip);
  
  if (attempts) {
    attempts.count += 1;
    attempts.lastAttempt = now;
  } else {
    loginAttempts.set(ip, { count: 1, lastAttempt: now });
  }
};

const clearFailedAttempts = (ip: string): void => {
  loginAttempts.delete(ip);
  blockedIPs.delete(ip);
};

const validateLoginInput = (username: string, password: string): string[] => {
  const errors: string[] = [];
  
  if (!username || typeof username !== 'string') {
    errors.push('Username is required');
  } else if (username.length < 2) {
    errors.push('Username must be at least 2 characters');
  } else if (username.length > 100) {
    errors.push('Username is too long');
  }
  
  if (!password || typeof password !== 'string') {
    errors.push('Password is required');
  } else if (password.length < 6) {
    errors.push('Password must be at least 6 characters');
  } else if (password.length > 200) {
    errors.push('Password is too long');
  }
  
  return errors;
};

const getClientIP = (event: any): string => {
  const headers = getHeaders(event);
  return (
    headers['x-forwarded-for']?.split(',')[0]?.trim() ||
    headers['x-real-ip'] ||
    headers['x-client-ip'] ||
    headers['cf-connecting-ip'] ||
    'unknown'
  );
};

export default defineEventHandler(async (event) => {
  try {
    const { username, password, rememberMe } = await readBody(event);
    const clientIP = getClientIP(event) || 'unknown';

    // Input validation
    const validationErrors = validateLoginInput(username, password);
    if (validationErrors.length > 0) {
      console.warn('❌ Validation failed:', validationErrors);
      throw createError({
        statusCode: 400,
        statusMessage: validationErrors.join(', ')
      });
    }

    // Rate limiting check
    const rateLimit = checkRateLimit(clientIP);
    if (!rateLimit.allowed) {
      console.warn('🚨 Rate limit exceeded for IP:', clientIP);
      throw createError({
        statusCode: 429,
        statusMessage: 'Too many login attempts. Please try again later.'
      });
    }

    const config = useRuntimeConfig();
    
    // Validate Keycloak configuration
    if (!config.keycloak?.issuer || !config.keycloak?.clientId || !config.keycloak?.clientSecret) {
      console.error('❌ Missing Keycloak configuration');
      throw createError({
        statusCode: 500,
        statusMessage: 'Authentication service configuration error'
      });
    }


    // Direct authentication with Keycloak using Resource Owner Password Credentials flow
    const tokenResponse = await fetch(`${config.keycloak.issuer}/protocol/openid-connect/token`, {
      method: 'POST',
      headers: { 
        'Content-Type': 'application/x-www-form-urlencoded',
        'User-Agent': 'MonacoUSA-Portal/1.0'
      },
      body: new URLSearchParams({
        grant_type: 'password',
        client_id: config.keycloak.clientId,
        client_secret: config.keycloak.clientSecret,
        username,
        password,
        scope: 'openid email profile roles'
      })
    });

    if (!tokenResponse.ok) {
      const errorData = await tokenResponse.json().catch(() => ({}));
      console.error('❌ Keycloak token error:', {
        status: tokenResponse.status,
        statusText: tokenResponse.statusText,
        error: errorData
      });

      // Record failed attempt for rate limiting
      recordFailedAttempt(clientIP);

      // Map Keycloak errors to user-friendly messages
      let errorMessage = 'Invalid username or password';
      if (errorData.error === 'invalid_grant') {
        errorMessage = 'Invalid username or password';
      } else if (errorData.error === 'unauthorized_client') {
        errorMessage = 'Authentication service error';
      } else if (errorData.error_description) {
        errorMessage = errorData.error_description;
      }

      throw createError({
        statusCode: 401,
        statusMessage: errorMessage
      });
    }

    const tokens = await tokenResponse.json();

    // Decode the access token to extract user information
    let tokenPayload = null;
    try {
      const tokenParts = tokens.access_token.split('.');
      const payload = JSON.parse(Buffer.from(tokenParts[1], 'base64').toString());
      tokenPayload = payload;
    } catch (err) {
      console.warn('⚠️ Could not decode access token:', err);
    }

    // Get user info from Keycloak
    const userResponse = await fetch(`${config.keycloak.issuer}/protocol/openid-connect/userinfo`, {
      headers: { 
        'Authorization': `Bearer ${tokens.access_token}`,
        'User-Agent': 'MonacoUSA-Portal/1.0'
      }
    });

    if (!userResponse.ok) {
      console.error('❌ Failed to get user info:', userResponse.status);
      throw createError({
        statusCode: 500,
        statusMessage: 'Failed to retrieve user information'
      });
    }

    const userInfo = await userResponse.json();

    // Extract groups/roles from multiple possible locations
    const extractGroups = (tokenPayload: any, userInfo: any): string[] => {
      const allGroups: string[] = [];
      
      // Check userInfo for groups (from userinfo endpoint)
      if (userInfo.groups && Array.isArray(userInfo.groups)) {
        allGroups.push(...userInfo.groups);
      }
      
      // Check userInfo for roles
      if (userInfo.roles && Array.isArray(userInfo.roles)) {
        allGroups.push(...userInfo.roles);
      }
      
      // Check token payload for realm_access.roles
      if (tokenPayload?.realm_access?.roles && Array.isArray(tokenPayload.realm_access.roles)) {
        allGroups.push(...tokenPayload.realm_access.roles);
      }
      
      // Check token payload for resource_access roles
      if (tokenPayload?.resource_access) {
        Object.keys(tokenPayload.resource_access).forEach(clientId => {
          const clientRoles = tokenPayload.resource_access[clientId]?.roles;
          if (clientRoles && Array.isArray(clientRoles)) {
            allGroups.push(...clientRoles);
          }
        });
      }
      
      // Check token payload for groups claim
      if (tokenPayload?.groups && Array.isArray(tokenPayload.groups)) {
        allGroups.push(...tokenPayload.groups);
      }
      
      // Remove duplicates and filter out default Keycloak roles
      const uniqueGroups = [...new Set(allGroups)].filter(group => 
        !['default-roles-monacousa', 'offline_access', 'uma_authorization'].includes(group)
      );
      
      return uniqueGroups;
    };

    // Tier determination logic - admin > board > user priority
    const determineTier = (groups: string[]): 'user' | 'board' | 'admin' => {
      if (groups.includes('admin')) {
        return 'admin';
      }
      if (groups.includes('board')) {
        return 'board';
      }
      return 'user'; // Default tier
    };

    // Extract groups from all possible sources
    const extractedGroups = extractGroups(tokenPayload, userInfo);

    // Create simplified session data to reduce cookie size
    const userTier = determineTier(extractedGroups);
    const userGroups = extractedGroups.length > 0 ? extractedGroups.slice(0, 10) : ['user']; // Limit groups to prevent large cookies
    
    const sessionData = {
      user: {
        id: userInfo.sub,
        email: userInfo.email,
        name: userInfo.name || `${userInfo.given_name || ''} ${userInfo.family_name || ''}`.trim(),
        firstName: userInfo.given_name,
        lastName: userInfo.family_name,
        username: userInfo.preferred_username || username,
        tier: userTier,
        groups: userGroups
      },
      tokens: {
        accessToken: tokens.access_token,
        refreshToken: tokens.refresh_token,
        expiresAt: Date.now() + (tokens.expires_in * 1000)
      },
      rememberMe: !!rememberMe,
      createdAt: Date.now(),
      lastActivity: Date.now()
    };

    // Create session with server-side storage
    const sessionManager = createSessionManager();
    
    try {
      // Create session and get cookie string
      const cookieString = sessionManager.createSession(sessionData, !!rememberMe);
      
      // Parse the cookie string to get the session ID
      const cookieParts = cookieString.split(';')[0].split('=');
      const sessionId = cookieParts[1];
      
      // Set the cookie using Nuxt's setCookie helper with mobile-compatible settings
      const maxAge = !!rememberMe ? 60 * 60 * 24 * 30 : 60 * 60 * 24 * 7; // 30 days vs 7 days
      const isProduction = process.env.NODE_ENV === 'production';
      
      console.log('🍪 Setting cookie with mobile-friendly settings:', {
        secure: isProduction,
        sameSite: 'lax',
        maxAge,
        rememberMe: !!rememberMe
      });
      
      setCookie(event, 'monacousa-session', sessionId, {
        httpOnly: true,
        secure: isProduction, // Only secure in production
        sameSite: 'lax', // Changed from 'none' for mobile compatibility
        maxAge,
        path: '/',
      });
      
    } catch (cookieError) {
      console.error('❌ Failed to set session cookie:', cookieError);
      throw createError({
        statusCode: 500,
        statusMessage: 'Failed to create session'
      });
    }
    
    // Clear failed attempts on successful login
    clearFailedAttempts(clientIP);
    
    console.log('✅ Login successful for user:', userInfo.email);

    // Add a small delay to ensure cookie is set
    await new Promise(resolve => setTimeout(resolve, 100));

    // Ensure we return a proper response with explicit status
    setResponseStatus(event, 200);
    setHeader(event, 'Content-Type', 'application/json');
    
    // Return a minimal response to prevent 502 errors
    return {
      success: true,
      redirectTo: '/dashboard',
      user: {
        email: userInfo.email,
        name: userInfo.name,
        tier: userTier
      }
    };

  } catch (error: any) {
    console.error('❌ Direct login error:', error);
    
    // If it's already a createError, just throw it
    if (error.statusCode) {
      throw error;
    }
    
    // Generic error for unexpected issues
    throw createError({
      statusCode: 500,
      statusMessage: 'Login failed. Please try again.'
    });
  }
});
