/**
 * Base Page Object Model for HVAC Testing Framework
 * 
 * Provides common page interaction methods with WordPress integration:
 * - Navigation and URL handling
 * - Element interaction with retry logic
 * - WordPress-specific waiting and assertions
 * - Screenshot and error handling utilities
 * 
 * @package HVAC_Community_Events
 * @version 2.0.0
 * @created 2025-08-27
 */

const { expect } = require('@playwright/test');
const ConfigManager = require('../../framework/core/ConfigManager');

class BasePage {
    constructor(page) {
        this.page = page;
        this.config = ConfigManager;
        this.baseUrl = this.config.get('app.baseUrl');
        this.defaultTimeout = this.config.get('framework.timeout');
        
        // Common WordPress selectors
        this.wpSelectors = {
            adminBar: '#wpadminbar',
            loadingSpinner: '.spinner, .loading',
            ajaxLoader: '.ajax-loader',
            errorMessage: '.error, .notice-error',
            successMessage: '.success, .notice-success, .updated',
            wpNonce: '[name="_wpnonce"]',
            loggedInBody: 'body.logged-in'
        };
    }
    
    /**
     * Navigate to URL with WordPress-aware waiting
     */
    async goto(url) {
        const fullUrl = url.startsWith('http') ? url : `${this.baseUrl}${url}`;
        console.log(`🔗 Navigating to: ${fullUrl}`);
        
        await this.page.goto(fullUrl, { 
            waitUntil: 'domcontentloaded',
            timeout: this.defaultTimeout 
        });
        
        // Wait for WordPress to be ready
        await this.waitForWordPressReady();
        
        // Check for WordPress errors
        await this.checkForWordPressErrors();
    }
    
    /**
     * Wait for WordPress to be ready
     */
    async waitForWordPressReady() {
        // Wait for DOM to be ready
        await this.page.waitForFunction('document.readyState === "complete"', {
            timeout: this.defaultTimeout
        });
        
        // Wait for jQuery if present
        try {
            await this.page.waitForFunction(
                'typeof jQuery === "undefined" || jQuery.active === 0',
                { timeout: 5000 }
            );
        } catch (error) {
            // jQuery may not be present, which is fine
        }
    }
    
    /**
     * Wait for AJAX requests to complete
     */
    async waitForAjax(timeout = 5000) {
        try {
            await this.page.waitForFunction(
                'window.hvacTestHelpers && window.hvacTestHelpers.waitForAjax()',
                { timeout }
            );
        } catch (error) {
            // Fallback wait
            await this.page.waitForTimeout(500);
        }
    }
    
    /**
     * Check for WordPress errors on page
     */
    async checkForWordPressErrors() {
        const errorSelectors = [
            '.wp-die-message',
            '.error-message',
            '.notice-error',
            'text=Fatal error',
            'text=Parse error',
            'text=Warning:',
            'text=Notice:'
        ];
        
        for (const selector of errorSelectors) {
            if (await this.isVisible(selector, { timeout: 1000 })) {
                const errorText = await this.getText(selector);
                console.warn(`⚠️ WordPress error detected: ${errorText}`);
            }
        }
    }
    
    /**
     * Find visible element from multiple selectors
     */
    async getVisibleSelector(selectors, options = {}) {
        const { timeout = 2000 } = options;
        
        for (const selector of selectors) {
            try {
                if (await this.isVisible(selector, { timeout: timeout / selectors.length })) {
                    return selector;
                }
            } catch (error) {
                continue;
            }
        }
        
        return null;
    }
    
    /**
     * Check if element is visible with multiple selector fallback
     */
    async isVisible(selectors, options = {}) {
        const selectorArray = Array.isArray(selectors) ? selectors : [selectors];
        const { timeout = 2000 } = options;
        
        for (const selector of selectorArray) {
            try {
                const element = this.page.locator(selector).first();
                await element.waitFor({ state: 'visible', timeout: timeout / selectorArray.length });
                return true;
            } catch (error) {
                continue;
            }
        }
        
        return false;
    }
    
    /**
     * Wait for element to be visible
     */
    async waitForVisible(selectors, options = {}) {
        const selectorArray = Array.isArray(selectors) ? selectors : [selectors];
        const { timeout = this.defaultTimeout } = options;
        
        for (const selector of selectorArray) {
            try {
                await this.page.locator(selector).first().waitFor({ 
                    state: 'visible', 
                    timeout: timeout / selectorArray.length 
                });
                return selector;
            } catch (error) {
                if (selector === selectorArray[selectorArray.length - 1]) {
                    throw new Error(`Element not found with any selector: ${selectorArray.join(', ')}`);
                }
                continue;
            }
        }
    }
    
    /**
     * Wait for element to be hidden
     */
    async waitForHidden(selectors, options = {}) {
        const selectorArray = Array.isArray(selectors) ? selectors : [selectors];
        const { timeout = this.defaultTimeout } = options;
        
        for (const selector of selectorArray) {
            try {
                await this.page.locator(selector).first().waitFor({ 
                    state: 'hidden', 
                    timeout: timeout / selectorArray.length 
                });
                return;
            } catch (error) {
                continue;
            }
        }
    }
    
    /**
     * Click element with multiple selector support
     */
    async click(selectors, options = {}) {
        const selectorArray = Array.isArray(selectors) ? selectors : [selectors];
        const { timeout = this.defaultTimeout, waitForNavigation = false } = options;
        
        for (const selector of selectorArray) {
            try {
                const element = this.page.locator(selector).first();
                await element.waitFor({ state: 'visible', timeout: timeout / selectorArray.length });
                
                if (waitForNavigation) {
                    await Promise.all([
                        this.page.waitForNavigation({ timeout }),
                        element.click()
                    ]);
                } else {
                    await element.click();
                }
                
                return;
            } catch (error) {
                if (selector === selectorArray[selectorArray.length - 1]) {
                    throw new Error(`Cannot click element with any selector: ${selectorArray.join(', ')}`);
                }
                continue;
            }
        }
    }
    
    /**
     * Fill form field with multiple selector support
     */
    async fill(selectors, value) {
        const selectorArray = Array.isArray(selectors) ? selectors : [selectors];
        
        for (const selector of selectorArray) {
            try {
                const element = this.page.locator(selector).first();
                await element.waitFor({ state: 'visible', timeout: 2000 });
                await element.fill(value);
                return;
            } catch (error) {
                if (selector === selectorArray[selectorArray.length - 1]) {
                    throw new Error(`Cannot fill field with any selector: ${selectorArray.join(', ')}`);
                }
                continue;
            }
        }
    }
    
    /**
     * Clear form field
     */
    async clear(selectors) {
        const selectorArray = Array.isArray(selectors) ? selectors : [selectors];
        
        for (const selector of selectorArray) {
            try {
                const element = this.page.locator(selector).first();
                await element.waitFor({ state: 'visible', timeout: 2000 });
                await element.clear();
                return;
            } catch (error) {
                continue;
            }
        }
    }
    
    /**
     * Get text content from element
     */
    async getText(selectors) {
        const selectorArray = Array.isArray(selectors) ? selectors : [selectors];
        
        for (const selector of selectorArray) {
            try {
                const element = this.page.locator(selector).first();
                await element.waitFor({ state: 'visible', timeout: 2000 });
                return await element.textContent();
            } catch (error) {
                continue;
            }
        }
        
        return '';
    }
    
    /**
     * Get input value from form field
     */
    async getInputValue(selectors) {
        const selectorArray = Array.isArray(selectors) ? selectors : [selectors];
        
        for (const selector of selectorArray) {
            try {
                const element = this.page.locator(selector).first();
                await element.waitFor({ state: 'visible', timeout: 2000 });
                return await element.inputValue();
            } catch (error) {
                continue;
            }
        }
        
        return '';
    }
    
    /**
     * Select option by text
     */
    async selectByText(selectors, text) {
        const selectorArray = Array.isArray(selectors) ? selectors : [selectors];
        
        for (const selector of selectorArray) {
            try {
                const element = this.page.locator(selector).first();
                await element.waitFor({ state: 'visible', timeout: 2000 });
                await element.selectOption({ label: text });
                return;
            } catch (error) {
                continue;
            }
        }
        
        throw new Error(`Cannot select option with text '${text}' from any selector: ${selectorArray.join(', ')}`);
    }
    
    /**
     * Select option by value
     */
    async selectByValue(selectors, value) {
        const selectorArray = Array.isArray(selectors) ? selectors : [selectors];
        
        for (const selector of selectorArray) {
            try {
                const element = this.page.locator(selector).first();
                await element.waitFor({ state: 'visible', timeout: 2000 });
                await element.selectOption(value);
                return;
            } catch (error) {
                continue;
            }
        }
        
        throw new Error(`Cannot select option with value '${value}' from any selector: ${selectorArray.join(', ')}`);
    }
    
    /**
     * Get selected value from dropdown
     */
    async getSelectedValue(selectors) {
        const selectorArray = Array.isArray(selectors) ? selectors : [selectors];
        
        for (const selector of selectorArray) {
            try {
                const element = this.page.locator(selector).first();
                await element.waitFor({ state: 'visible', timeout: 2000 });
                return await element.inputValue();
            } catch (error) {
                continue;
            }
        }
        
        return '';
    }
    
    /**
     * Check checkbox or radio button
     */
    async check(selectors) {
        const selectorArray = Array.isArray(selectors) ? selectors : [selectors];
        
        for (const selector of selectorArray) {
            try {
                const element = this.page.locator(selector).first();
                await element.waitFor({ state: 'visible', timeout: 2000 });
                await element.check();
                return;
            } catch (error) {
                continue;
            }
        }
    }
    
    /**
     * Uncheck checkbox or radio button
     */
    async uncheck(selectors) {
        const selectorArray = Array.isArray(selectors) ? selectors : [selectors];
        
        for (const selector of selectorArray) {
            try {
                const element = this.page.locator(selector).first();
                await element.waitFor({ state: 'visible', timeout: 2000 });
                await element.uncheck();
                return;
            } catch (error) {
                continue;
            }
        }
    }
    
    /**
     * Get locator for element
     */
    locator(selectors) {
        const selectorArray = Array.isArray(selectors) ? selectors : [selectors];
        return this.page.locator(selectorArray.join(', '));
    }
    
    /**
     * Wait for URL change or specific URL pattern
     */
    async waitForUrl(pattern, options = {}) {
        const { timeout = this.defaultTimeout } = options;
        await this.page.waitForURL(pattern, { timeout });
    }
    
    /**
     * Wait for URL to change from current
     */
    async waitForUrlChange(timeout = this.defaultTimeout) {
        const currentUrl = this.page.url();
        await this.page.waitForFunction(
            (oldUrl) => window.location.href !== oldUrl,
            currentUrl,
            { timeout }
        );
    }
    
    /**
     * Verify user role from page elements
     */
    async verifyUserRole(expectedRole) {
        // Check body class for role
        const hasRoleClass = await this.page.evaluate((role) => {
            return document.body.classList.contains(`role-${role}`);
        }, expectedRole);
        
        if (hasRoleClass) {
            return true;
        }
        
        // Check admin bar user info
        if (await this.isVisible(this.wpSelectors.adminBar)) {
            const userInfo = await this.getText('#wp-admin-bar-my-account .display-name');
            console.log(`Current user display name: ${userInfo}`);
        }
        
        // Additional WordPress role verification can be added here
        return hasRoleClass;
    }
    
    /**
     * Verify breadcrumbs navigation
     */
    async verifyBreadcrumbs(expectedPath) {
        const breadcrumbSelectors = [
            '.hvac-breadcrumb',
            '.breadcrumb',
            '[data-testid="breadcrumb"]',
            '.breadcrumb-nav'
        ];
        
        for (const selector of breadcrumbSelectors) {
            if (await this.isVisible(selector)) {
                const breadcrumbText = await this.getText(selector);
                
                for (const pathItem of expectedPath) {
                    if (!breadcrumbText.includes(pathItem)) {
                        console.warn(`⚠️ Breadcrumb missing: ${pathItem}`);
                        return false;
                    }
                }
                
                console.log(`✅ Breadcrumbs verified: ${breadcrumbText}`);
                return true;
            }
        }
        
        console.log('⚠️ No breadcrumbs found');
        return false;
    }
    
    /**
     * Take screenshot with context
     */
    async takeScreenshot(name, options = {}) {
        const { fullPage = false } = options;
        
        try {
            const screenshotPath = `test-results/${name}-${Date.now()}.png`;
            await this.page.screenshot({
                path: screenshotPath,
                fullPage
            });
            
            console.log(`📸 Screenshot saved: ${screenshotPath}`);
            return screenshotPath;
        } catch (error) {
            console.warn('Could not take screenshot:', error.message);
            return null;
        }
    }
    
    /**
     * Scroll element into view
     */
    async scrollIntoView(selectors) {
        const selectorArray = Array.isArray(selectors) ? selectors : [selectors];
        
        for (const selector of selectorArray) {
            try {
                const element = this.page.locator(selector).first();
                await element.scrollIntoViewIfNeeded();
                return;
            } catch (error) {
                continue;
            }
        }
    }
    
    /**
     * Handle WordPress nonce verification
     */
    async verifyNonce(expectedAction) {
        if (await this.isVisible(this.wpSelectors.wpNonce)) {
            const nonce = await this.page.locator(this.wpSelectors.wpNonce).getAttribute('value');
            console.log(`🔒 WordPress nonce present: ${nonce.substring(0, 8)}...`);
            return true;
        }
        
        console.warn('⚠️ WordPress nonce not found');
        return false;
    }
    
    /**
     * Wait for network idle state
     */
    async waitForNetworkIdle(timeout = 5000) {
        await this.page.waitForLoadState('networkidle', { timeout });
    }
    
    /**
     * Get current page title
     */
    async getPageTitle() {
        return await this.page.title();
    }
    
    /**
     * Get current URL
     */
    getCurrentUrl() {
        return this.page.url();
    }
    
    /**
     * Refresh page with WordPress readiness check
     */
    async refresh() {
        await this.page.reload({ waitUntil: 'domcontentloaded' });
        await this.waitForWordPressReady();
        await this.checkForWordPressErrors();
    }
}

module.exports = BasePage;