/**
 * Enhanced Authentication Manager for HVAC Testing Framework
 * 
 * Provides comprehensive authentication management with:
 * - Storage state pre-generation and management
 * - Role-based authentication with WordPress integration
 * - Session persistence and validation
 * - Parallel test execution support with isolated auth states
 * 
 * @package HVAC_Community_Events
 * @version 2.0.0
 * @created 2025-08-27
 */

const fs = require('fs').promises;
const path = require('path');
const { chromium } = require('playwright');
const ConfigManager = require('./ConfigManager');

class AuthManager {
    /**
     * Authentication manager instance
     */
    static instance = null;
    
    /**
     * Get authentication manager instance (Singleton pattern)
     */
    static getInstance() {
        if (!AuthManager.instance) {
            AuthManager.instance = new AuthManager();
        }
        return AuthManager.instance;
    }
    
    constructor() {
        this.config = ConfigManager;
        this.storageStatesDir = path.resolve(__dirname, '../../fixtures/storage-states');
        this.authValidated = new Map(); // Cache for validated auth states
        this.initializeStorageDirectory();
    }
    
    /**
     * Initialize storage states directory
     */
    async initializeStorageDirectory() {
        try {
            await fs.mkdir(this.storageStatesDir, { recursive: true });
        } catch (error) {
            console.warn('Could not create storage states directory:', error.message);
        }
    }
    
    /**
     * Pre-generate storage states for all user roles
     * This method should be called during test setup to create auth states
     */
    async preGenerateStorageStates() {
        console.log('🔐 Pre-generating authentication storage states...');
        
        const roles = ['trainer', 'masterTrainer', 'admin'];
        const results = [];
        
        for (const role of roles) {
            try {
                console.log(`  📋 Generating storage state for: ${role}`);
                const storageState = await this.generateStorageState(role);
                results.push({ role, success: true, path: storageState });
                console.log(`  ✅ Generated: ${role}`);
            } catch (error) {
                console.error(`  ❌ Failed to generate ${role}:`, error.message);
                results.push({ role, success: false, error: error.message });
            }
        }
        
        // Summary
        const successful = results.filter(r => r.success).length;
        const failed = results.filter(r => !r.success).length;
        
        console.log(`\n📊 Storage state generation complete:`);
        console.log(`  ✅ Successful: ${successful}`);
        console.log(`  ❌ Failed: ${failed}`);
        
        if (failed > 0) {
            console.warn('Some storage states failed to generate. Tests may fall back to fresh login.');
        }
        
        return results;
    }
    
    /**
     * Generate storage state for a specific user role
     */
    async generateStorageState(role) {
        const browser = await chromium.launch(this.config.getBrowserConfig());
        const context = await browser.newContext();
        const page = await context.newPage();
        
        try {
            // Get user configuration
            const userConfig = this.config.getUserConfig(role);
            if (!userConfig || !userConfig.username || !userConfig.password) {
                throw new Error(`Missing user configuration for role: ${role}`);
            }
            
            // Navigate to login page
            const loginUrl = this.getLoginUrl(role);
            await page.goto(loginUrl, { waitUntil: 'networkidle' });
            
            // Perform login
            await this.performLogin(page, userConfig, role);
            
            // Verify authentication
            await this.verifyAuthentication(page, role);
            
            // Save storage state
            const storageStatePath = this.getStorageStatePath(role);
            await context.storageState({ path: storageStatePath });
            
            console.log(`💾 Saved storage state: ${storageStatePath}`);
            
            return storageStatePath;
            
        } finally {
            await browser.close();
        }
    }
    
    /**
     * Load authentication storage state for user role
     */
    async loadStorageState(role, context) {
        const storageStatePath = this.getStorageStatePath(role);
        
        try {
            // Check if storage state file exists and is recent
            const stats = await fs.stat(storageStatePath);
            const ageHours = (Date.now() - stats.mtime) / (1000 * 60 * 60);
            
            if (ageHours > 24) {
                console.log(`🔄 Storage state for ${role} is ${ageHours.toFixed(1)} hours old, regenerating...`);
                return await this.generateStorageState(role);
            }
            
            // Load storage state
            await context.addInitScript(`
                // Set storage state metadata
                window.HVAC_AUTH_ROLE = '${role}';
                window.HVAC_AUTH_LOADED = true;
            `);
            
            const storageState = JSON.parse(await fs.readFile(storageStatePath, 'utf8'));
            await context.addCookies(storageState.cookies || []);
            
            console.log(`📂 Loaded storage state for: ${role}`);
            return storageStatePath;
            
        } catch (error) {
            console.log(`⚠️ Could not load storage state for ${role}: ${error.message}`);
            console.log('Falling back to fresh authentication...');
            return null;
        }
    }
    
    /**
     * Validate that authentication storage state is still valid
     */
    async validateStorageState(page, role) {
        // Check cache first
        const cacheKey = `${role}-${this.getStorageStatePath(role)}`;
        if (this.authValidated.has(cacheKey)) {
            const cached = this.authValidated.get(cacheKey);
            const ageMinutes = (Date.now() - cached.timestamp) / (1000 * 60);
            
            if (ageMinutes < 5) { // Cache for 5 minutes
                return cached.valid;
            }
        }
        
        try {
            await this.verifyAuthentication(page, role);
            this.authValidated.set(cacheKey, { valid: true, timestamp: Date.now() });
            return true;
        } catch (error) {
            this.authValidated.set(cacheKey, { valid: false, timestamp: Date.now() });
            console.log(`❌ Storage state validation failed for ${role}: ${error.message}`);
            return false;
        }
    }
    
    /**
     * Authenticate user with storage state management
     */
    async authenticate(page, role, options = {}) {
        const context = page.context();
        
        // Try to load existing storage state
        if (!options.forceLogin) {
            const storageStatePath = await this.loadStorageState(role, context);
            if (storageStatePath) {
                // Navigate to expected page and validate
                const defaultPage = this.config.getUserConfig(role).defaultPage;
                await page.goto(`${this.config.get('app.baseUrl')}${defaultPage}`);
                
                if (await this.validateStorageState(page, role)) {
                    console.log(`✅ Authentication restored for ${role} using storage state`);
                    return { method: 'storage-state', role, valid: true };
                }
            }
        }
        
        // Fall back to fresh login
        console.log(`🔑 Performing fresh login for: ${role}`);
        return await this.freshLogin(page, role, options);
    }
    
    /**
     * Perform fresh login and optionally save storage state
     */
    async freshLogin(page, role, options = {}) {
        const userConfig = this.config.getUserConfig(role);
        if (!userConfig || !userConfig.username || !userConfig.password) {
            throw new Error(`Missing user configuration for role: ${role}`);
        }
        
        // Navigate to login page
        const loginUrl = this.getLoginUrl(role);
        await page.goto(loginUrl, { waitUntil: 'networkidle' });
        
        // Perform login
        await this.performLogin(page, userConfig, role);
        
        // Verify authentication
        await this.verifyAuthentication(page, role);
        
        // Save storage state for future use
        if (!options.skipStorageStateSave) {
            try {
                const storageStatePath = this.getStorageStatePath(role);
                await page.context().storageState({ path: storageStatePath });
                console.log(`💾 Updated storage state for: ${role}`);
            } catch (error) {
                console.warn('Could not save storage state:', error.message);
            }
        }
        
        console.log(`✅ Fresh login successful for: ${role}`);
        return { method: 'fresh-login', role, valid: true };
    }
    
    /**
     * Perform login on page with user configuration
     */
    async performLogin(page, userConfig, role) {
        // Wait for login form
        await page.waitForSelector('input[type="email"], input[name="log"], #user_login', { timeout: 10000 });
        
        // Fill email/username
        const emailSelectors = [
            'input[type="email"]',
            'input[name="log"]', 
            '#user_login',
            'input[name="username"]'
        ];
        
        let emailFilled = false;
        for (const selector of emailSelectors) {
            try {
                const field = page.locator(selector);
                if (await field.isVisible()) {
                    await field.fill(userConfig.username || userConfig.email);
                    emailFilled = true;
                    break;
                }
            } catch (error) {
                // Continue to next selector
            }
        }
        
        if (!emailFilled) {
            throw new Error('Could not find email/username field');
        }
        
        // Fill password
        const passwordSelectors = [
            'input[type="password"]',
            'input[name="pwd"]',
            '#user_pass',
            'input[name="password"]'
        ];
        
        let passwordFilled = false;
        for (const selector of passwordSelectors) {
            try {
                const field = page.locator(selector);
                if (await field.isVisible()) {
                    await field.fill(userConfig.password);
                    passwordFilled = true;
                    break;
                }
            } catch (error) {
                // Continue to next selector
            }
        }
        
        if (!passwordFilled) {
            throw new Error('Could not find password field');
        }
        
        // Submit form
        const submitSelectors = [
            'button[type="submit"]',
            'input[type="submit"]',
            '#wp-submit',
            '.login-submit button',
            '.submit input'
        ];
        
        let submitted = false;
        for (const selector of submitSelectors) {
            try {
                const button = page.locator(selector);
                if (await button.isVisible()) {
                    await Promise.all([
                        page.waitForURL(url => 
                            !url.includes('/wp-login.php') && 
                            !url.includes('/training-login/'),
                            { timeout: this.config.get('framework.timeout') }
                        ),
                        button.click()
                    ]);
                    submitted = true;
                    break;
                }
            } catch (error) {
                // Continue to next selector
            }
        }
        
        if (!submitted) {
            throw new Error('Could not find or click submit button');
        }
        
        // Wait for page to load
        await page.waitForLoadState('networkidle', { timeout: 10000 });
    }
    
    /**
     * Verify authentication for user role
     */
    async verifyAuthentication(page, role) {
        const userConfig = this.config.getUserConfig(role);
        const expectedPage = userConfig.defaultPage;
        
        // Check if we're on the expected page or similar
        const currentUrl = page.url();
        
        // Role-specific verification
        switch (role) {
            case 'trainer':
                if (!currentUrl.includes('/trainer/')) {
                    // Navigate to trainer dashboard
                    await page.goto(`${this.config.get('app.baseUrl')}/trainer/dashboard/`);
                }
                await page.waitForSelector('.hvac-trainer-nav, .trainer-dashboard, h1:has-text("Dashboard")', { timeout: 10000 });
                break;
                
            case 'masterTrainer':
                if (!currentUrl.includes('/master-trainer/')) {
                    // Navigate to master trainer dashboard
                    await page.goto(`${this.config.get('app.baseUrl')}/master-trainer/master-dashboard/`);
                }
                await page.waitForSelector('.hvac-master-dashboard, .master-trainer-nav, h1:has-text("Master Dashboard")', { timeout: 10000 });
                break;
                
            case 'admin':
                if (!currentUrl.includes('/wp-admin/')) {
                    // Navigate to WordPress admin
                    await page.goto(`${this.config.get('app.baseUrl')}/wp-admin/`);
                }
                await page.waitForSelector('#wpadminbar, .wp-admin, #wpbody', { timeout: 10000 });
                break;
                
            default:
                throw new Error(`Unknown role: ${role}`);
        }
        
        // Check for login error indicators
        const errorSelectors = [
            '.error', '.login-error', '#login_error', 
            '.error-message', 'text=Invalid username or password'
        ];
        
        for (const selector of errorSelectors) {
            if (await page.locator(selector).isVisible().catch(() => false)) {
                throw new Error('Login failed - error message visible');
            }
        }
    }
    
    /**
     * Get login URL for role
     */
    getLoginUrl(role) {
        const baseUrl = this.config.get('app.baseUrl');
        
        if (role === 'admin') {
            return `${baseUrl}${this.config.get('wordpress.loginPath')}`;
        } else {
            return `${baseUrl}${this.config.get('wordpress.customLoginPath')}`;
        }
    }
    
    /**
     * Get storage state file path for role
     */
    getStorageStatePath(role) {
        const environment = this.config.getEnvironment();
        return path.join(this.storageStatesDir, `${role}-${environment}.json`);
    }
    
    /**
     * Clear all storage states
     */
    async clearStorageStates() {
        try {
            const files = await fs.readdir(this.storageStatesDir);
            const jsonFiles = files.filter(f => f.endsWith('.json'));
            
            for (const file of jsonFiles) {
                await fs.unlink(path.join(this.storageStatesDir, file));
            }
            
            console.log(`🗑️ Cleared ${jsonFiles.length} storage state files`);
        } catch (error) {
            console.warn('Could not clear storage states:', error.message);
        }
    }
    
    /**
     * Clear validation cache
     */
    clearValidationCache() {
        this.authValidated.clear();
        console.log('🗑️ Cleared authentication validation cache');
    }
    
    /**
     * Get authentication status summary
     */
    async getAuthStatus() {
        const roles = ['trainer', 'masterTrainer', 'admin'];
        const status = {};
        
        for (const role of roles) {
            const storageStatePath = this.getStorageStatePath(role);
            try {
                const stats = await fs.stat(storageStatePath);
                const ageHours = (Date.now() - stats.mtime) / (1000 * 60 * 60);
                status[role] = {
                    exists: true,
                    path: storageStatePath,
                    ageHours: ageHours.toFixed(2),
                    fresh: ageHours < 1
                };
            } catch (error) {
                status[role] = {
                    exists: false,
                    path: storageStatePath,
                    error: error.message
                };
            }
        }
        
        return status;
    }
    
    /**
     * Logout current user
     */
    async logout(page) {
        const logoutSelectors = [
            'a[href*="logout"]',
            'text=Logout',
            'text=Log Out',
            'text=Sign Out',
            '.logout-link'
        ];
        
        for (const selector of logoutSelectors) {
            try {
                const logoutLink = page.locator(selector);
                if (await logoutLink.isVisible()) {
                    await logoutLink.click();
                    await page.waitForURL(url => 
                        url.includes('/wp-login.php') || 
                        url.includes('/training-login/') ||
                        url.includes('/logged-out'),
                        { timeout: 5000 }
                    );
                    console.log('✅ Successfully logged out');
                    return;
                }
            } catch (error) {
                // Continue to next selector
            }
        }
        
        // Fallback: clear cookies and navigate to login
        await page.context().clearCookies();
        await page.goto(`${this.config.get('app.baseUrl')}/wp-login.php`);
        console.log('⚠️ Forced logout by clearing cookies');
    }
}

// Export singleton instance
module.exports = AuthManager.getInstance();