// server/api/auth/keycloak-callback.ts - EXTENDED SESSION FIX

// Add this at the top of the file (after imports)
const SESSION_DURATION = 1 * 60 * 60; // 1 hour in seconds (3600 seconds)
// Or use one of these alternatives:
// const SESSION_DURATION = 24 * 60 * 60;        // 1 day
// const SESSION_DURATION = 30 * 24 * 60 * 60;   // 30 days
// const SESSION_DURATION = 12 * 60 * 60;        // 12 hours
// const SESSION_DURATION = 7 * 24 * 60 * 60;   // 7 days

export default defineEventHandler(async (event) => {
    try {
        const config = useRuntimeConfig();
        const query = getQuery(event);

        console.log('🔄 === KEYCLOAK CALLBACK STARTED ===');
        console.log('📋 Query parameters:', query);

        const code = query.code as string;
        const state = query.state as string;
        const error = query.error as string;
        const storedState = getCookie(event, 'oauth_state');

        if (error) {
            console.error('❌ OAuth error from Keycloak:', error);
            const errorDescription = query.error_description as string;
            console.error('❌ Error description:', errorDescription);

            const errorMsg = encodeURIComponent(`Keycloak error: ${error} - ${errorDescription || 'Please try again'}`);
            return sendRedirect(event, `/auth/login?error=${errorMsg}`);
        }

        console.log('📝 Code received:', !!code);
        console.log('🎲 State from URL:', state);
        console.log('🎲 State from cookie:', storedState);
        console.log('🎲 State validation:', state === storedState);

        if (!state || state !== storedState) {
            console.error('❌ Invalid state parameter - possible CSRF attack');
            console.error('   Expected:', storedState);
            console.error('   Received:', state);

            const errorMsg = encodeURIComponent('Security validation failed. Please try logging in again.');
            return sendRedirect(event, `/auth/login?error=${errorMsg}`);
        }

        deleteCookie(event, 'oauth_state');

        if (!code) {
            console.error('❌ Authorization code not provided');
            const errorMsg = encodeURIComponent('No authorization code received from Keycloak.');
            return sendRedirect(event, `/auth/login?error=${errorMsg}`);
        }

        // Validate Keycloak configuration
        if (!config.keycloakIssuer) {
            console.error('❌ KEYCLOAK_ISSUER is not configured');
            const errorMsg = encodeURIComponent('Keycloak server is not configured. Please contact administrator.');
            return sendRedirect(event, `/auth/login?error=${errorMsg}`);
        }

        if (!config.keycloakClientId || !config.keycloakClientSecret) {
            console.error('❌ Keycloak client credentials are not configured');
            const errorMsg = encodeURIComponent('Keycloak client credentials are missing. Please contact administrator.');
            return sendRedirect(event, `/auth/login?error=${errorMsg}`);
        }

        const tokenUrl = `${config.keycloakIssuer}/protocol/openid-connect/token`;
        const redirectUri = `${config.public.authUrl}/api/auth/keycloak-callback`;

        console.log('🔗 Token URL:', tokenUrl);
        console.log('🔗 Redirect URI:', redirectUri);
        console.log('🔑 Client ID:', config.keycloakClientId ? '***configured***' : 'MISSING');

        const tokenPayload = new URLSearchParams({
            grant_type: 'authorization_code',
            client_id: config.keycloakClientId,
            client_secret: config.keycloakClientSecret,
            code,
            redirect_uri: redirectUri,
        });

        let tokenResponse;
        try {
            // Create abort controller for timeout (compatible with all Node.js versions)
            const controller = new AbortController();
            const timeoutId = setTimeout(() => controller.abort(), 30000); // 30 second timeout

            tokenResponse = await fetch(tokenUrl, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded',
                },
                body: tokenPayload,
                signal: controller.signal,
            });

            clearTimeout(timeoutId);
        } catch (fetchError: any) {
            console.error('❌ Fetch error details:');
            console.error('   - Error type:', fetchError.name);
            console.error('   - Error message:', fetchError.message);
            console.error('   - Token URL attempted:', tokenUrl);
            
            // Provide more specific error messages
            let errorMsg = 'Failed to connect to authentication server.';
            if (fetchError.name === 'AbortError' || fetchError.message.includes('timeout')) {
                errorMsg = 'Authentication server timeout. Please try again.';
            } else if (fetchError.message.includes('ENOTFOUND') || fetchError.message.includes('getaddrinfo')) {
                errorMsg = 'Cannot reach authentication server. Please check network connection.';
            } else if (fetchError.message.includes('ECONNREFUSED')) {
                errorMsg = 'Authentication server refused connection. Server may be down.';
            } else if (fetchError.message.includes('certificate') || fetchError.message.includes('SSL')) {
                errorMsg = 'SSL certificate error. Please contact administrator.';
            }
            
            const encodedError = encodeURIComponent(errorMsg);
            return sendRedirect(event, `/auth/login?error=${encodedError}`);
        }

        if (!tokenResponse.ok) {
            const errorText = await tokenResponse.text();
            console.error('❌ Token exchange failed:', errorText);
            const errorMsg = encodeURIComponent(`Token exchange failed: ${tokenResponse.status} - Please check Keycloak configuration`);
            return sendRedirect(event, `/auth/login?error=${errorMsg}`);
        }

        const tokens = await tokenResponse.json();
        
        let idTokenPayload;
        try {
            idTokenPayload = JSON.parse(
                Buffer.from(tokens.id_token.split('.')[1], 'base64').toString()
            );
        } catch (decodeError) {
            console.error('❌ Failed to decode ID token:', decodeError);
            const errorMsg = encodeURIComponent('Invalid ID token format');
            return sendRedirect(event, `/auth/login?error=${errorMsg}`);
        }
        
        // Store minimal session data in cookie to reduce size
        // The ID token contains user info, so we can decode it when needed
        const sessionData = {
            // Store only essential user info (can be decoded from ID token if needed)
            user: {
                id: idTokenPayload.sub,
                email: idTokenPayload.email,
                name: idTokenPayload.name || idTokenPayload.preferred_username,
                preferred_username: idTokenPayload.preferred_username,
            },
            // Store tokens - these are necessary for API calls
            // Note: These JWT tokens are large, but necessary for authentication
            accessToken: tokens.access_token,
            idToken: tokens.id_token,
            refreshToken: tokens.refresh_token,
            // Session metadata
            expiresAt: Date.now() + (SESSION_DURATION * 1000),
            createdAt: Date.now(),
        };

        // Determine if we should use secure cookies
        // For localhost, always use secure: false
        const isSecure = process.env.NODE_ENV === 'production' && 
                         event.node.req.headers['x-forwarded-proto'] === 'https';

        console.log('🔗 Setting session cookie with secure flag:', isSecure);
        console.log('⏱️ Session duration:', SESSION_DURATION, 'seconds');
        console.log('🌐 Request host:', event.node.req.headers.host);
        console.log('🔒 Protocol:', event.node.req.headers['x-forwarded-proto'] || 'http');

        // Set cookie with proper settings for localhost
        // For localhost HTTP, we need secure: false and sameSite: 'lax'
        // IMPORTANT: Ensure domain is not set for localhost (allows cookie to work)
        const cookieOptions: any = {
            httpOnly: true,
            secure: isSecure, 
            sameSite: 'lax' as const, 
            maxAge: SESSION_DURATION,
            path: '/',
            // Explicitly don't set domain for localhost - this is important!
            // Setting domain to 'localhost' can cause cookies to not work
        };

        // For localhost, don't set domain (allows cookie to work on localhost)
        // Only set domain in production if needed
        if (process.env.NODE_ENV === 'production' && !event.node.req.headers.host?.includes('localhost')) {
            // Optionally set domain in production
            // cookieOptions.domain = '.yourdomain.com';
        }

        // Store session in server-side store and use session ID in cookie
        // This avoids cookie size limits (4KB)
        const { createSession } = await import('~/server/utils/sessionStore');
        const sessionId = createSession(sessionData);
        
        console.log('💾 Session stored server-side with ID:', sessionId.substring(0, 8) + '...');
        console.log('📦 Session ID cookie size: ~64 bytes (much smaller!)');
        
        // Store only the session ID in the cookie (much smaller)
        setCookie(event, 'user_session', sessionId, cookieOptions);
        
        console.log('✅ Session ID cookie set in response headers (will be available in next request)');

        console.log('✅ Session cookie created successfully');
        console.log('🍪 Cookie details:');
        console.log('   - Path: /');
        console.log('   - Secure:', isSecure);
        console.log('   - SameSite: lax');
        console.log('   - HttpOnly: true');
        console.log('   - MaxAge:', SESSION_DURATION, 'seconds');
        console.log('   - Host:', event.node.req.headers.host);
        
        // Auto-sync user data to database (first time login check)
        // Pass session createdAt as loginTime to sync function
        try {
            const { syncUserFromTokens } = await import('~/server/utils/userSync');
            const result = syncUserFromTokens(tokens.id_token, tokens.access_token, sessionData.createdAt);
            console.log(`✅ User auto-sync on login: ${result.action} - ${result.message}`);
        } catch (syncError: any) {
            // Don't fail the login if sync fails, just log it
            console.error('⚠️ Failed to auto-sync user on login:', syncError);
        }
        
        // IMPORTANT: Ensure cookie is set before redirect
        // The cookie should be in the Set-Cookie header of the redirect response
        console.log('↪️ Redirecting to dashboard with cookie in response headers...');
        
        // Note: In H3/Nitro, setCookie automatically adds Set-Cookie header to response
        // The cookie will be available in the browser after the redirect
        // We can't verify it in the same request, but it should be set correctly
        
        // Use sendRedirect - it should include the Set-Cookie header
        // The browser will receive the cookie and include it in the next request
        return sendRedirect(event, '/dashboard?authenticated=true', 302);

    } catch (error: any) {
        console.error('❌ === CALLBACK ERROR ===');
        console.error('❌ Error message:', error.message);
        console.error('❌ Error stack:', error.stack);
        console.error('❌ ==================');

        const errorMsg = encodeURIComponent(`Authentication failed: ${error.message}`);
        return sendRedirect(event, `/auth/login?error=${errorMsg}`);
    }
});