/**
 * Base Page Object - Foundation for all page objects
 * Provides common functionality for WordPress pages
 */

const { getBrowserManager } = require('../browser/BrowserManager');

class BasePage {
    constructor(page = null) {
        this.page = page || getBrowserManager().getCurrentPage();
        this.url = '';
        this.title = '';
        this.selectors = {};
    }

    /**
     * Navigate to this page
     * @param {Object} options - Navigation options
     * @returns {Promise<void>}
     */
    async navigate(options = {}) {
        if (!this.url) {
            throw new Error('Page URL not defined');
        }

        await this.page.goto(this.url, {
            waitUntil: 'networkidle',
            timeout: 30000,
            ...options
        });

        await this.waitForPageLoad();
    }

    /**
     * Wait for page to be loaded and ready
     * @returns {Promise<void>}
     */
    async waitForPageLoad() {
        // Wait for document ready
        await this.page.waitForLoadState('domcontentloaded');
        
        // Wait for any WordPress-specific loading
        await this.waitForWordPressReady();
        
        // Wait for any page-specific loading
        await this.waitForPageReady();
    }

    /**
     * Wait for WordPress-specific elements to be ready
     * @returns {Promise<void>}
     */
    async waitForWordPressReady() {
        try {
            // Wait for WordPress admin bar or body class
            await this.page.waitForSelector('body.logged-in, body.wp-core-ui, #wpadminbar', {
                timeout: 10000
            });
        } catch (error) {
            // Not a WordPress page or user not logged in - continue
        }

        // Wait for jQuery if present
        try {
            await this.page.waitForFunction(() => 
                window.jQuery !== undefined || window.$ !== undefined, 
                { timeout: 5000 }
            );
        } catch (error) {
            // jQuery not present - continue
        }
    }

    /**
     * Wait for page-specific elements to be ready
     * Override in subclasses for page-specific waiting
     * @returns {Promise<void>}
     */
    async waitForPageReady() {
        // Override in subclasses
    }

    /**
     * Check if element exists
     * @param {string} selector - CSS selector
     * @returns {Promise<boolean>}
     */
    async hasElement(selector) {
        try {
            const element = await this.page.$(selector);
            return element !== null;
        } catch (error) {
            return false;
        }
    }

    /**
     * Wait for element to be visible
     * @param {string} selector - CSS selector
     * @param {number} timeout - Timeout in milliseconds
     * @returns {Promise<void>}
     */
    async waitForElement(selector, timeout = 30000) {
        await this.page.waitForSelector(selector, { 
            visible: true, 
            timeout 
        });
    }

    /**
     * Wait for element to be hidden/removed
     * @param {string} selector - CSS selector
     * @param {number} timeout - Timeout in milliseconds
     * @returns {Promise<void>}
     */
    async waitForElementHidden(selector, timeout = 30000) {
        await this.page.waitForSelector(selector, { 
            hidden: true, 
            timeout 
        });
    }

    /**
     * Click element with retry and wait
     * @param {string} selector - CSS selector
     * @param {Object} options - Click options
     * @returns {Promise<void>}
     */
    async clickElement(selector, options = {}) {
        await this.waitForElement(selector);
        
        // Scroll element into view
        await this.page.locator(selector).scrollIntoViewIfNeeded();
        
        // Wait for element to be stable
        await this.page.locator(selector).waitFor({ state: 'visible' });
        
        // Click with retry
        await this.page.click(selector, {
            timeout: 10000,
            ...options
        });
    }

    /**
     * Fill input field with validation
     * @param {string} selector - CSS selector
     * @param {string} value - Value to fill
     * @param {Object} options - Fill options
     * @returns {Promise<void>}
     */
    async fillField(selector, value, options = {}) {
        await this.waitForElement(selector);
        
        // Clear existing content
        await this.page.fill(selector, '', { timeout: 10000 });
        
        // Fill with new value
        await this.page.fill(selector, value, { 
            timeout: 10000,
            ...options 
        });
        
        // Verify the value was set
        const actualValue = await this.page.inputValue(selector);
        if (actualValue !== value) {
            throw new Error(`Failed to fill field ${selector}. Expected: ${value}, Got: ${actualValue}`);
        }
    }

    /**
     * Select option from dropdown
     * @param {string} selector - CSS selector
     * @param {string|Object} option - Option value or object with label/value
     * @returns {Promise<void>}
     */
    async selectOption(selector, option) {
        await this.waitForElement(selector);
        
        if (typeof option === 'string') {
            await this.page.selectOption(selector, option);
        } else {
            await this.page.selectOption(selector, { 
                label: option.label, 
                value: option.value 
            });
        }
    }

    /**
     * Get text content of element
     * @param {string} selector - CSS selector
     * @returns {Promise<string>}
     */
    async getElementText(selector) {
        await this.waitForElement(selector);
        return await this.page.textContent(selector);
    }

    /**
     * Get attribute value of element
     * @param {string} selector - CSS selector
     * @param {string} attribute - Attribute name
     * @returns {Promise<string|null>}
     */
    async getElementAttribute(selector, attribute) {
        await this.waitForElement(selector);
        return await this.page.getAttribute(selector, attribute);
    }

    /**
     * Check if element is visible
     * @param {string} selector - CSS selector
     * @returns {Promise<boolean>}
     */
    async isElementVisible(selector) {
        try {
            return await this.page.isVisible(selector);
        } catch (error) {
            return false;
        }
    }

    /**
     * Check if element is enabled
     * @param {string} selector - CSS selector
     * @returns {Promise<boolean>}
     */
    async isElementEnabled(selector) {
        try {
            return await this.page.isEnabled(selector);
        } catch (error) {
            return false;
        }
    }

    /**
     * Wait for page URL to match pattern
     * @param {RegExp|string} pattern - URL pattern to match
     * @param {number} timeout - Timeout in milliseconds
     * @returns {Promise<void>}
     */
    async waitForUrl(pattern, timeout = 30000) {
        await this.page.waitForURL(pattern, { timeout });
    }

    /**
     * Get current page URL
     * @returns {string}
     */
    getCurrentUrl() {
        return this.page.url();
    }

    /**
     * Get page title
     * @returns {Promise<string>}
     */
    async getPageTitle() {
        return await this.page.title();
    }

    /**
     * Take screenshot of current page
     * @param {string} filename - Screenshot filename
     * @returns {Promise<string>} Path to screenshot
     */
    async takeScreenshot(filename) {
        const browserManager = getBrowserManager();
        return await browserManager.takeScreenshot(filename);
    }

    /**
     * Execute JavaScript on page
     * @param {string|Function} script - JavaScript to execute
     * @param {...*} args - Arguments to pass to script
     * @returns {Promise<*>}
     */
    async executeScript(script, ...args) {
        return await this.page.evaluate(script, ...args);
    }

    /**
     * Wait for AJAX requests to complete
     * @param {number} timeout - Timeout in milliseconds
     * @returns {Promise<void>}
     */
    async waitForAjaxComplete(timeout = 10000) {
        try {
            await this.page.waitForFunction(() => {
                // Check if jQuery is available and has no active requests
                if (window.jQuery) {
                    return window.jQuery.active === 0;
                }
                // Fallback: check if no pending fetch requests
                return !window.fetch || window.fetch.length === 0;
            }, { timeout });
        } catch (error) {
            console.warn('AJAX wait timeout - continuing anyway');
        }
    }

    /**
     * Scroll to element
     * @param {string} selector - CSS selector
     * @returns {Promise<void>}
     */
    async scrollToElement(selector) {
        await this.waitForElement(selector);
        await this.page.locator(selector).scrollIntoViewIfNeeded();
    }

    /**
     * Hover over element
     * @param {string} selector - CSS selector
     * @returns {Promise<void>}
     */
    async hoverElement(selector) {
        await this.waitForElement(selector);
        await this.page.hover(selector);
    }

    /**
     * Double click element
     * @param {string} selector - CSS selector
     * @returns {Promise<void>}
     */
    async doubleClickElement(selector) {
        await this.waitForElement(selector);
        await this.page.dblclick(selector);
    }

    /**
     * Right click element
     * @param {string} selector - CSS selector
     * @returns {Promise<void>}
     */
    async rightClickElement(selector) {
        await this.waitForElement(selector);
        await this.page.click(selector, { button: 'right' });
    }
}

module.exports = BasePage;