import { Page, expect } from '@playwright/test';

export class TestHelper {
    static async waitForPageLoad(page: Page, timeout: number = 30000): Promise<void> {
        await page.waitForLoadState('networkidle', { timeout });
        await page.waitForLoadState('domcontentloaded', { timeout });
    }

    static async waitForElementVisible(
        page: Page,
        selector: string,
        timeout: number = 10000
    ): Promise<void> {
        await expect(page.locator(selector)).toBeVisible({ timeout });
    }

    static async waitForElementHidden(
        page: Page,
        selector: string,
        timeout: number = 10000
    ): Promise<void> {
        await expect(page.locator(selector)).toBeHidden({ timeout });
    }

    static async waitForTextContent(
        page: Page,
        selector: string,
        text: string,
        timeout: number = 10000
    ): Promise<void> {
        await expect(page.locator(selector)).toContainText(text, { timeout });
    }

    static async clickElement(page: Page, selector: string, timeout: number = 10000): Promise<void> {
        await page.click(selector, { timeout });
    }

    static async fillInput(
        page: Page,
        selector: string,
        value: string,
        timeout: number = 10000
    ): Promise<void> {
        await page.fill(selector, value, { timeout });
    }

    static async selectOption(
        page: Page,
        selector: string,
        value: string,
        timeout: number = 10000
    ): Promise<void> {
        await page.selectOption(selector, value, { timeout });
    }

    static async checkCheckbox(
        page: Page,
        selector: string,
        timeout: number = 10000
    ): Promise<void> {
        await page.check(selector, { timeout });
    }

    static async uncheckCheckbox(
        page: Page,
        selector: string,
        timeout: number = 10000
    ): Promise<void> {
        await page.uncheck(selector, { timeout });
    }

    static async uploadFile(
        page: Page,
        selector: string,
        filePath: string,
        timeout: number = 10000
    ): Promise<void> {
        await page.setInputFiles(selector, filePath, { timeout });
    }

    static async takeScreenshot(
        page: Page,
        filename: string,
        fullPage: boolean = false
    ): Promise<void> {
        await page.screenshot({
            path: `test-results/screenshots/${filename}`,
            fullPage,
        });
    }

    static async waitForUrl(
        page: Page,
        urlPattern: string | RegExp,
        timeout: number = 30000
    ): Promise<void> {
        await page.waitForURL(urlPattern, { timeout });
    }

    static async reloadPage(page: Page, timeout: number = 30000): Promise<void> {
        await page.reload({ waitUntil: 'networkidle', timeout });
    }

    static async navigateTo(page: Page, url: string, timeout: number = 30000): Promise<void> {
        await page.goto(url, { waitUntil: 'networkidle', timeout });
    }

    static async waitForDialog(page: Page, timeout: number = 10000): Promise<void> {
        await page.waitForEvent('dialog', { timeout });
    }

    static async handleDialog(page: Page, accept: boolean = true): Promise<void> {
        page.on('dialog', async (dialog) => {
            if (accept) {
                await dialog.accept();
            } else {
                await dialog.dismiss();
            }
        });
    }

    static async waitForToast(
        page: Page,
        message: string,
        timeout: number = 5000
    ): Promise<void> {
        await expect(page.locator('.el-message')).toContainText(message, { timeout });
    }

    static async waitForSuccessMessage(page: Page, timeout: number = 5000): Promise<void> {
        await expect(page.locator('.el-message--success')).toBeVisible({ timeout });
    }

    static async waitForErrorMessage(page: Page, timeout: number = 5000): Promise<void> {
        await expect(page.locator('.el-message--error')).toBeVisible({ timeout });
    }

    static async getElementText(page: Page, selector: string): Promise<string> {
        const text = await page.textContent(selector);
        return text || '';
    }

    static async getElementCount(page: Page, selector: string): Promise<number> {
        return await page.locator(selector).count();
    }

    static async isElementVisible(page: Page, selector: string): Promise<boolean> {
        return await page.locator(selector).isVisible();
    }

    static async isElementEnabled(page: Page, selector: string): Promise<boolean> {
        return await page.locator(selector).isEnabled();
    }

    static async scrollToElement(page: Page, selector: string): Promise<void> {
        await page.locator(selector).scrollIntoViewIfNeeded();
    }

    static async hoverElement(page: Page, selector: string): Promise<void> {
        await page.hover(selector);
    }

    static async doubleClickElement(page: Page, selector: string): Promise<void> {
        await page.dblclick(selector);
    }

    static async rightClickElement(page: Page, selector: string): Promise<void> {
        await page.click(selector, { button: 'right' });
    }

    static async waitForApiResponse(
        page: Page,
        urlPattern: string | RegExp,
        timeout: number = 30000
    ): Promise<void> {
        await page.waitForResponse(
            (response) => !!response.url().match(urlPattern),
            { timeout }
        );
    }

    static async getApiResponse(
        page: Page,
        urlPattern: string | RegExp,
        timeout: number = 30000
    ): Promise<any> {
        const response = await page.waitForResponse(
            (response) => !!response.url().match(urlPattern),
            { timeout }
        );
        return await response.json();
    }

    static async mockApiResponse(
        page: Page,
        urlPattern: string | RegExp,
        mockData: any
    ): Promise<void> {
        await page.route(urlPattern, async (route) => {
            await route.fulfill({
                status: 200,
                contentType: 'application/json',
                body: JSON.stringify(mockData),
            });
        });
    }

    static async executeScript(page: Page, script: string): Promise<any> {
        return await page.evaluate(script);
    }

    static async setLocalStorage(page: Page, key: string, value: string): Promise<void> {
        await page.evaluate(
            ({ key, value }) => {
                localStorage.setItem(key, value);
            },
            { key, value }
        );
    }

    static async getLocalStorage(page: Page, key: string): Promise<string | null> {
        return await page.evaluate((key) => localStorage.getItem(key), key);
    }

    static async clearLocalStorage(page: Page): Promise<void> {
        await page.evaluate(() => localStorage.clear());
    }

    static async setSessionStorage(page: Page, key: string, value: string): Promise<void> {
        await page.evaluate(
            ({ key, value }) => {
                sessionStorage.setItem(key, value);
            },
            { key, value }
        );
    }

    static async clearSessionStorage(page: Page): Promise<void> {
        await page.evaluate(() => sessionStorage.clear());
    }

    static async clearCookies(page: Page): Promise<void> {
        await page.context().clearCookies();
    }

    static async clearAllStorage(page: Page): Promise<void> {
        await this.clearLocalStorage(page);
        await this.clearSessionStorage(page);
        await this.clearCookies(page);
    }

    static async getAuthToken(page: Page): Promise<string> {
        const token = await this.getLocalStorage(page, 'token');
        if (!token) {
            const user = await this.getLocalStorage(page, 'user');
            if (user) {
                const userData = JSON.parse(user);
                return userData.token || '';
            }
        }
        return token || '';
    }
}
