import { ICustomerDetails } from 'safelite-playwright-core';
import { Soft } from 'safelite-playwright-core';
import { waitUntil } from 'safelite-playwright-core';
import test, { expect, type Locator, type Page } from '@playwright/test';
import { error } from 'console';
import { ITestData } from 'framework/TestData';

/**
 * Base class for all page objects.
 * Provides common functionality for interacting with pages.
 */
export class BasePage {
    // Common locators
    readonly page: Page;
    readonly continueButton: Locator;
    readonly backButton: Locator;
    readonly pageSpinner: Locator;
    readonly buttonLoadSpin: Locator;
    readonly hamburgerMenu: Locator;
    readonly progressBar: Locator;

    constructor(page: Page) {
        this.page = page;
        this.continueButton = page.locator('[id="infoBox"]').getByRole('button');
        this.backButton = page.locator('[id="infoBox"]').getByRole('link');
        this.pageSpinner = page.getByRole('status');
        this.buttonLoadSpin = page.getByRole('alert');
        this.hamburgerMenu = this.page.getByRole('button', { name: 'Hamburger Menu (modal window)' });
        this.progressBar = this.page.locator('.progress-bar-outer .progress-bar-inner');
    }

    async nextPage() {
        await waitUntil(async () => {
            return (await this.continueButton.getAttribute('aria-disabled')) !== 'true'
        });

        await this.continueButton.click();

        await waitUntil(async () => {
            let loaderElements = await this.page.locator('button .loader, .buy-loader, timeout, .modal-loader').all();
            return !(await Promise.any(loaderElements.map(el => el.isVisible())).catch(() => false));
        });
    }


    async previousPage() {
        const startingUrl = this.page.url();
        await expect(async () => {
            const currentUrl = this.page.url();
            if (currentUrl === startingUrl) {
                await this.backButton.click({ timeout: 1000 });
            }
            expect(currentUrl).not.toEqual(startingUrl);
        }).toPass({ timeout: 240_000 });
    }

    async fillAndValidate(element: Locator, value: string) {
        await expect(async () => {
            var text = await element.textContent();
            if (text !== value) {
                await element.clear();
                await element.fill(value);
            }
            await expect(element).toHaveValue(value);
        }).toPass();
    }

    async clickWithRetry(element, page) {
        const timeout = 5000; // milli seconds
        const startTime = Date.now();
        while (Date.now() - startTime < timeout) {
            try {
                if (await element.isEnabled()) {
                    await element.click();
                    await element.keyboard.press('Tab');
                    return; // Exit loop if click succeeds
                }
            } catch (error) {
                // Ignore error and retry
            }
            await page.waitForTimeout(100); // Small delay before retrying
        }
        console.log(`Failed to click the the element within ${timeout / 1000} seconds` + error);
    }

    async logReferralNumber() {
        let mainLocalStorage = JSON.parse(await this.page.evaluate('localStorage.getItem(\'main\')'));
        let referralNumber = mainLocalStorage.order.referralNumber as number;
        let referralSequenceNumber = mainLocalStorage.order.referralSequenceNumber as number;
        if (referralNumber == null) {
            for (let i = 1; i <= 20; i++) {
                if (!referralNumber == null) break;
                await this.page.waitForTimeout(500);
                mainLocalStorage = JSON.parse(await this.page.evaluate('localStorage.getItem(\'main\')'));
                referralNumber = mainLocalStorage.order.referralNumber as number;
                referralSequenceNumber = mainLocalStorage.order.referralSequenceNumber as number;
            }
        }

        await test.step(`Referral Number:${referralNumber} Referral Sequence Number:${referralSequenceNumber}`, async () => {
            console.log(`Referral Number:${referralNumber}`);
            console.log(`Referral Sequence Number:${referralSequenceNumber}`);
        });
    }

    async mockScheduleResponseForEarlyBird(customerDetails: ICustomerDetails) {

        const apiUrl = `https://digitalapi.${process.env['PLAYWRIGHT_ENV']!.replace('sys', 'test').toLowerCase()}.safelite.io/schedule/api/v1/schedule/mobile-time-slots`;
        await this.page.route(apiUrl, async (route) => {
            const currentDate = new Date().toISOString().split('T')[0]; // e.g., "2025-07-23"
            if (route.request().postDataJSON().startDate === currentDate) {
                const response = await route.fetch();
                const responseBody = await response.json();

                responseBody.days.forEach((day: any) => {
                    day.timeSlots.forEach((slot: any) => {
                        if (slot.id.includes("AM")) {
                            slot.offerPremium = true;
                        }
                    });
                });

                customerDetails.apptDate = responseBody.days.find((day: any) => day.timeSlots.some((slot: any) => slot.offerPremium === true)).date || undefined;

                // Mock the response
                await route.fulfill({
                    response,
                    body: JSON.stringify(responseBody),
                });
            }
        });
    }

    async getRepairPartsTotal(testData: Partial<ITestData>) {
        const apiUrl = `https://digitalapi.${process.env['PLAYWRIGHT_ENV']!.replace('sys', 'test').toLowerCase()}.safelite.io/price/api/v1/price/order-items`;
        await this.page.on('response', async (response) => {
            const orderItemRequest = response.request();
            if (response.request().url() === apiUrl && orderItemRequest.postDataJSON().lineItems.some(item => item.partNumber === "WSREPAIR")) {
                const responseBody = await response.json();
                const targetParts = ['WSREPAIR']; // ["SUPPLIES-REPAIR", "WSREPAIR"]; 
                testData.totalAmount = responseBody.lineItems
                    .filter(item => targetParts.includes(item.partNumber))
                    .reduce((sum: number, item: any) => {
                        return sum + item.laborAmount + item.sellingPrice + item.kitPrice;
                    }, 0).toFixed(2);
            }
        });
        testData.totalAmount! > 0 ? console.log(`Total Amount: ${testData.totalAmount}`) : console.error('No repair parts found in the order items.');
    }

    async validateProgressBar(progressPercentage: string, timeout: number = 60000) {
        // This section has been commented out until progress bar work is completed for parity.

        await waitUntil(async () => {
            let loaderElements = await this.page.locator('button .loader, .buy-loader, timeout, .modal-loader').all();
            return !(await Promise.any(loaderElements.map(el => el.isVisible())).catch(() => false));
        });

        // Take a screenshot of the page before validating the progress bar
        await this.page.screenshot({ path: `test-results\\ortoni-data\\progress-bar-${Date.now()}.png`, fullPage: true });
        // Wait until the progress bar element is attached and visible

        const actualProgressPercentage = await this.progressBar.evaluate(
            async (element) => {
                await new Promise(resolve => setTimeout(resolve, 200));
                return element.style.width || "Not Found";
            }
        );
        Soft.expect(actualProgressPercentage).toBe(progressPercentage);
        console.log(`Progress Bar Percentage: Actual - ${actualProgressPercentage} vs Expected - ${progressPercentage}`);
    }
}