/**
 * Base Test Class for HVAC Testing Framework
 * 
 * Provides standardized test foundation with:
 * - WordPress-aware setup and teardown
 * - Screenshot and video management
 * - Database isolation and cleanup
 * - Error handling and recovery
 * - Consistent test reporting
 * 
 * @package HVAC_Community_Events
 * @version 2.0.0
 * @created 2025-08-27
 */

const { test, expect } = require('@playwright/test');
const fs = require('fs').promises;
const path = require('path');
const ConfigManager = require('./ConfigManager');
const AuthManager = require('./AuthManager');
const WordPressUtils = require('../utils/WordPressUtils');
const ScreenshotManager = require('../utils/ScreenshotManager');

class BaseTest {
    constructor() {
        this.config = ConfigManager;
        this.authManager = AuthManager;
        this.wpUtils = new WordPressUtils();
        this.screenshotManager = new ScreenshotManager();
        this.testStartTime = null;
        this.testContext = null;
        this.testMetadata = {};
    }
    
    /**
     * Configure test with metadata and options
     */
    configure(metadata = {}) {
        this.testMetadata = {
            category: metadata.category || 'general',
            priority: metadata.priority || 'medium',
            tags: metadata.tags || [],
            requirements: metadata.requirements || [],
            author: metadata.author || 'automated',
            ...metadata
        };
        
        return this;
    }
    
    /**
     * Standard test setup - call this in beforeEach
     */
    async setup(page, testInfo) {
        this.testStartTime = Date.now();
        this.testContext = {
            page,
            testInfo,
            testId: this.generateTestId(testInfo),
            screenshotPath: this.getScreenshotPath(testInfo)
        };
        
        // Set up error handling
        this.setupErrorHandling(page);
        
        // Set up WordPress environment
        await this.setupWordPressEnvironment(page);
        
        // Initialize test data if needed
        if (this.config.get('testData.seedData')) {
            await this.setupTestData();
        }
        
        // Take initial screenshot if configured
        if (this.config.get('media.screenshotMode') === 'all') {
            await this.screenshotManager.capture(page, 'test-start', this.testContext.screenshotPath);
        }
        
        console.log(`🧪 Test setup complete: ${testInfo.title}`);
    }
    
    /**
     * Standard test teardown - call this in afterEach
     */
    async teardown(page, testInfo) {
        const testDuration = Date.now() - this.testStartTime;
        const testPassed = testInfo.status === 'passed';
        
        try {
            // Take final screenshot if test failed or if configured for all tests
            const screenshotMode = this.config.get('media.screenshotMode');
            if (!testPassed || screenshotMode === 'all') {
                await this.screenshotManager.capture(
                    page, 
                    testPassed ? 'test-end' : 'test-failure', 
                    this.testContext.screenshotPath
                );
            }
            
            // Clean up test data if configured
            if (this.config.get('testData.cleanupAfterTests')) {
                await this.cleanupTestData();
            }
            
            // Log test completion
            const status = testPassed ? '✅ PASSED' : '❌ FAILED';
            console.log(`${status} ${testInfo.title} (${testDuration}ms)`);
            
            // Record test metrics
            await this.recordTestMetrics(testInfo, testDuration, testPassed);
            
        } catch (error) {
            console.error('Error during test teardown:', error.message);
        }
    }
    
    /**
     * Set up error handling for the page
     */
    setupErrorHandling(page) {
        // Handle console errors
        page.on('console', msg => {
            if (msg.type() === 'error') {
                console.error(`🔴 Console Error: ${msg.text()}`);
            }
        });
        
        // Handle page errors
        page.on('pageerror', error => {
            console.error(`🔴 Page Error: ${error.message}`);
        });
        
        // Handle failed requests (optional)
        page.on('requestfailed', request => {
            if (request.url().includes(this.config.get('app.baseUrl'))) {
                console.warn(`⚠️ Request Failed: ${request.method()} ${request.url()}`);
            }
        });
    }
    
    /**
     * Set up WordPress environment for test
     */
    async setupWordPressEnvironment(page) {
        // Set WordPress-specific headers and context
        await page.setExtraHTTPHeaders({
            'User-Agent': 'HVAC-Testing-Framework/2.0 Playwright',
            'X-Test-Framework': 'HVAC-WordPress-Tests'
        });
        
        // Add WordPress helper scripts
        await page.addInitScript(`
            window.HVAC_TEST_MODE = true;
            window.HVAC_TEST_ID = '${this.testContext.testId}';
            window.HVAC_TEST_START = ${this.testStartTime};
            
            // WordPress-specific test helpers
            window.hvacTestHelpers = {
                waitForAjax: function() {
                    return new Promise(resolve => {
                        if (typeof jQuery !== 'undefined' && jQuery.active === 0) {
                            resolve();
                        } else if (typeof jQuery !== 'undefined') {
                            jQuery(document).ajaxStop(resolve);
                        } else {
                            // Fallback for non-jQuery AJAX
                            setTimeout(resolve, 100);
                        }
                    });
                },
                
                waitForWordPress: function() {
                    return new Promise(resolve => {
                        if (document.readyState === 'complete') {
                            resolve();
                        } else {
                            window.addEventListener('load', resolve);
                        }
                    });
                },
                
                triggerWordPressEvent: function(eventName, data) {
                    if (typeof jQuery !== 'undefined') {
                        jQuery(document).trigger(eventName, data);
                    }
                }
            };
        `);
        
        // Flush rewrite rules if configured
        if (this.config.get('wordpress.flushRewriteRules')) {
            await this.wpUtils.flushRewriteRules();
        }
        
        // Clear cache if configured
        if (this.config.get('wordpress.clearCache')) {
            await this.wpUtils.clearCache();
        }
    }
    
    /**
     * Set up test data for the test
     */
    async setupTestData() {
        // This method can be overridden by specific test classes
        // to set up role-specific test data
        
        console.log('📋 Setting up test data...');
        
        // Load fixtures if available
        const fixtures = this.config.get('testData.fixtures');
        if (fixtures && fixtures.users) {
            await this.loadUserFixtures(fixtures.users);
        }
    }
    
    /**
     * Clean up test data after test
     */
    async cleanupTestData() {
        console.log('🧹 Cleaning up test data...');
        
        // Clean up test-specific data
        await this.wpUtils.cleanupTestData(this.testContext.testId);
    }
    
    /**
     * Load user fixtures for testing
     */
    async loadUserFixtures(fixturesPath) {
        try {
            const fixtures = JSON.parse(await fs.readFile(fixturesPath, 'utf8'));
            // Process user fixtures as needed
            console.log(`📂 Loaded user fixtures: ${Object.keys(fixtures).length} users`);
        } catch (error) {
            console.warn('Could not load user fixtures:', error.message);
        }
    }
    
    /**
     * Authenticate as specific user role
     */
    async authenticateAs(page, role, options = {}) {
        console.log(`🔐 Authenticating as: ${role}`);
        return await this.authManager.authenticate(page, role, options);
    }
    
    /**
     * Wait for WordPress-specific conditions
     */
    async waitForWordPress(page, condition = 'ready') {
        switch (condition) {
            case 'ready':
                await page.waitForFunction('document.readyState === "complete"');
                break;
                
            case 'ajax':
                await page.waitForFunction(`
                    window.hvacTestHelpers && window.hvacTestHelpers.waitForAjax()
                `);
                break;
                
            case 'dom-ready':
                await page.waitForFunction('document.readyState !== "loading"');
                break;
                
            case 'network-idle':
                await page.waitForLoadState('networkidle');
                break;
                
            default:
                throw new Error(`Unknown WordPress condition: ${condition}`);
        }
    }
    
    /**
     * Take screenshot with context
     */
    async takeScreenshot(page, name = 'screenshot', fullPage = false) {
        return await this.screenshotManager.capture(
            page, 
            name, 
            this.testContext.screenshotPath,
            { fullPage }
        );
    }
    
    /**
     * Assert WordPress-specific conditions
     */
    async assertWordPressState(page, assertions) {
        if (assertions.authenticated) {
            // Check if user is authenticated
            const isLoggedIn = await page.evaluate(() => {
                return document.body.classList.contains('logged-in') ||
                       document.querySelector('#wpadminbar') !== null ||
                       window.location.pathname.includes('/wp-admin/');
            });
            expect(isLoggedIn).toBe(true);
        }
        
        if (assertions.role) {
            // Verify user has expected role
            const hasRole = await page.evaluate((expectedRole) => {
                return document.body.classList.contains(`role-${expectedRole}`) ||
                       window.HVAC_AUTH_ROLE === expectedRole;
            }, assertions.role);
            expect(hasRole).toBe(true);
        }
        
        if (assertions.capability) {
            // Check if user has specific capability
            await expect(page.locator(`[data-capability="${assertions.capability}"]`)).toBeVisible();
        }
        
        if (assertions.nonce) {
            // Verify WordPress nonce is present
            const nonceExists = await page.evaluate((nonceName) => {
                return document.querySelector(`[name="_wpnonce"]`) !== null ||
                       document.querySelector(`[name="${nonceName}"]`) !== null;
            }, assertions.nonce);
            expect(nonceExists).toBe(true);
        }
    }
    
    /**
     * Generate unique test ID
     */
    generateTestId(testInfo) {
        const timestamp = Date.now();
        const testName = testInfo.title.replace(/[^a-zA-Z0-9]/g, '-').toLowerCase();
        return `hvac-test-${testName}-${timestamp}`;
    }
    
    /**
     * Get screenshot path for test
     */
    getScreenshotPath(testInfo) {
        const screenshotDir = this.config.get('media.screenshotDir');
        const testName = testInfo.title.replace(/[^a-zA-Z0-9]/g, '-').toLowerCase();
        const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
        return path.join(screenshotDir, `${testName}-${timestamp}`);
    }
    
    /**
     * Record test metrics for reporting
     */
    async recordTestMetrics(testInfo, duration, passed) {
        const metrics = {
            testId: this.testContext.testId,
            title: testInfo.title,
            category: this.testMetadata.category,
            priority: this.testMetadata.priority,
            tags: this.testMetadata.tags,
            duration,
            passed,
            timestamp: new Date().toISOString(),
            environment: this.config.getEnvironment(),
            metadata: this.testMetadata
        };
        
        // Write metrics to results directory
        const resultsDir = this.config.get('reporting.outputDir');
        const metricsFile = path.join(resultsDir, 'test-metrics.jsonl');
        
        try {
            await fs.mkdir(resultsDir, { recursive: true });
            await fs.appendFile(metricsFile, JSON.stringify(metrics) + '\n');
        } catch (error) {
            console.warn('Could not record test metrics:', error.message);
        }
    }
    
    /**
     * Helper method to create WordPress-aware test
     */
    static create(title, testFn, metadata = {}) {
        return test(title, async ({ page }, testInfo) => {
            const baseTest = new BaseTest();
            baseTest.configure(metadata);
            
            try {
                await baseTest.setup(page, testInfo);
                await testFn(page, testInfo, baseTest);
            } finally {
                await baseTest.teardown(page, testInfo);
            }
        });
    }
    
    /**
     * Helper method to create WordPress-aware describe block
     */
    static describe(title, testSuite, metadata = {}) {
        return test.describe(title, () => {
            // Set up common hooks for the test suite
            test.beforeAll(async () => {
                console.log(`📦 Starting test suite: ${title}`);
            });
            
            test.afterAll(async () => {
                console.log(`📦 Completed test suite: ${title}`);
            });
            
            // Run the test suite
            testSuite();
        });
    }
}

module.exports = BaseTest;