/**
 * Authentication Fixtures for Playwright Tests
 * 
 * Provides reusable authentication fixtures with state management:
 * - Automatic authentication setup
 * - State persistence across tests
 * - Role-based test isolation
 * - Performance optimization
 * - Error handling
 * 
 * @package HVAC_Community_Events
 * @version 3.0.0
 * @created 2025-08-20
 */

const { test: base, expect } = require('@playwright/test');
const LoginPage = require('./LoginPage');
const { 
    getAuthStatePath, 
    saveAuthState, 
    clearAuthState,
    verifyAuthentication,
    getUserConfig 
} = require('./auth.setup');

/**
 * Extended test with authentication fixtures
 */
const test = base.extend({
    /**
     * Authenticated trainer page
     */
    authenticatedTrainerPage: async ({ browser }, use) => {
        const context = await browser.newContext();
        const page = await context.newPage();
        const loginPage = new LoginPage(page);
        
        try {
            await loginPage.loginWithStateManagement('trainer', context);
            await use(page);
        } finally {
            await context.close();
        }
    },
    
    /**
     * Authenticated master trainer page
     */
    authenticatedMasterTrainerPage: async ({ browser }, use) => {
        const context = await browser.newContext();
        const page = await context.newPage();
        const loginPage = new LoginPage(page);
        
        try {
            await loginPage.loginWithStateManagement('master_trainer', context);
            await use(page);
        } finally {
            await context.close();
        }
    },
    
    /**
     * Authenticated admin page
     */
    authenticatedAdminPage: async ({ browser }, use) => {
        const context = await browser.newContext();
        const page = await context.newPage();
        const loginPage = new LoginPage(page);
        
        try {
            await loginPage.loginWithStateManagement('admin', context);
            await use(page);
        } finally {
            await context.close();
        }
    },
    
    /**
     * Login page helper
     */
    loginPage: async ({ page }, use) => {
        const loginPage = new LoginPage(page);
        await use(loginPage);
    },
    
    /**
     * Multi-role context for testing role switching
     */
    multiRoleContext: async ({ browser }, use) => {
        const contexts = {};
        const pages = {};
        
        try {
            // Create contexts for each role
            for (const userType of ['trainer', 'master_trainer', 'admin']) {
                contexts[userType] = await browser.newContext();
                pages[userType] = await contexts[userType].newPage();
                const loginPage = new LoginPage(pages[userType]);
                await loginPage.loginWithStateManagement(userType, contexts[userType]);
            }
            
            await use({ contexts, pages });
        } finally {
            // Clean up all contexts
            for (const context of Object.values(contexts)) {
                await context.close();
            }
        }
    }
});

/**
 * Authentication test helpers
 */
const authHelpers = {
    /**
     * Login to page as specific user type
     * @param {Page} page - Playwright page
     * @param {string} userType - User type
     * @param {Object} options - Login options
     */
    async loginAs(page, userType, options = {}) {
        const loginPage = new LoginPage(page);
        await loginPage.login(userType, options);
    },
    
    /**
     * Verify user authentication and role
     * @param {Page} page - Playwright page
     * @param {string} expectedUserType - Expected user type
     */
    async verifyAuth(page, expectedUserType) {
        await verifyAuthentication(page, expectedUserType);
    },
    
    /**
     * Setup authentication for test suite
     * @param {string} userType - Default user type for suite
     */
    setupAuth(userType = 'trainer') {
        return {
            beforeEach: async ({ page }) => {
                await authHelpers.loginAs(page, userType);
            },
            afterEach: async ({ page }) => {
                // Optional: logout after each test
                if (process.env.LOGOUT_AFTER_TEST) {
                    const loginPage = new LoginPage(page);
                    await loginPage.logout();
                }
            }
        };
    },
    
    /**
     * Create authentication test context with state management
     * @param {Browser} browser - Playwright browser
     * @param {string} userType - User type
     * @returns {Object} Context and page with authentication
     */
    async createAuthContext(browser, userType) {
        // Try to use saved authentication state
        const authStatePath = await getAuthStatePath(userType);
        let context;
        
        if (authStatePath) {
            try {
                context = await browser.newContext({ storageState: authStatePath });
                const page = await context.newPage();
                
                // Verify saved state is still valid
                await verifyAuthentication(page, userType);
                console.log(`✅ Using saved auth state for ${userType}`);
                
                return { context, page };
            } catch (error) {
                console.log(`⚠️ Saved auth state invalid for ${userType}, creating fresh context`);
                await context?.close();
            }
        }
        
        // Create fresh context and login
        context = await browser.newContext();
        const page = await context.newPage();
        const loginPage = new LoginPage(page);
        
        await loginPage.login(userType);
        await saveAuthState(userType, context);
        
        return { context, page };
    },
    
    /**
     * Clear all authentication states (for test cleanup)
     */
    async clearAllAuthStates() {
        await clearAuthState();
    },
    
    /**
     * Get user configuration for testing
     * @param {string} userType - User type
     * @returns {Object} User configuration
     */
    getUserConfig(userType) {
        return getUserConfig(userType);
    }
};

/**
 * Authentication test scenarios
 */
const authScenarios = {
    /**
     * Test authentication for all user types
     * @param {Function} testFn - Test function to run for each user type
     */
    forAllUserTypes(testFn) {
        const userTypes = ['trainer', 'master_trainer', 'admin'];
        
        for (const userType of userTypes) {
            test(`${userType} authentication`, async ({ browser }) => {
                const { context, page } = await authHelpers.createAuthContext(browser, userType);
                
                try {
                    await testFn(page, userType);
                } finally {
                    await context.close();
                }
            });
        }
    },
    
    /**
     * Test role-based access control
     * @param {Object} roleTests - Map of userType to test function
     */
    forRoleAccess(roleTests) {
        for (const [userType, testFn] of Object.entries(roleTests)) {
            test(`${userType} role access`, async ({ browser }) => {
                const { context, page } = await authHelpers.createAuthContext(browser, userType);
                
                try {
                    await testFn(page, userType);
                } finally {
                    await context.close();
                }
            });
        }
    },
    
    /**
     * Test unauthorized access (should be blocked)
     * @param {string} authorizedUserType - User type that should have access
     * @param {string[]} unauthorizedUserTypes - User types that should NOT have access
     * @param {Function} testFn - Test function that should fail for unauthorized users
     */
    testUnauthorizedAccess(authorizedUserType, unauthorizedUserTypes, testFn) {
        // Test authorized access
        test(`${authorizedUserType} authorized access`, async ({ browser }) => {
            const { context, page } = await authHelpers.createAuthContext(browser, authorizedUserType);
            
            try {
                await testFn(page, authorizedUserType, true); // Should succeed
            } finally {
                await context.close();
            }
        });
        
        // Test unauthorized access
        for (const userType of unauthorizedUserTypes) {
            test(`${userType} unauthorized access blocked`, async ({ browser }) => {
                const { context, page } = await authHelpers.createAuthContext(browser, userType);
                
                try {
                    await expect(async () => {
                        await testFn(page, userType, false); // Should fail
                    }).rejects.toThrow();
                } finally {
                    await context.close();
                }
            });
        }
    }
};

module.exports = { 
    test, 
    expect, 
    authHelpers, 
    authScenarios,
    LoginPage
};