import { expect, type Locator, type Page } from '@playwright/test';
import { BasePage } from './BasePage';
import { IAppointmentDetails, ServiceLocation } from 'safelite-playwright-core';
import { formatDate, formatTime } from 'safelite-playwright-core';
import { AppointmentTimeslot  } from 'safelite-playwright-core';
import { ProgressBarPercentages } from 'framework/localTypes/Enums';
import { time } from 'console';
import { step } from 'framework/localTypes/Step';
import { ITestData } from 'framework/TestData';

export class SchedulePage extends BasePage {
    readonly page: Page;
    readonly inShopButton: Locator;
    readonly mobileButton: Locator;
    readonly RecalWarningMessage1: Locator;
    readonly RecalWarningMessage2: Locator;
    readonly militaryWarningMessage: Locator;
    readonly changeZipButton: Locator;
    readonly updateZipTextBox: Locator;
    readonly safeliteShopsList: Locator;
    readonly searchButton: Locator;
    readonly storeAddressText: Locator;
    readonly saveLocationButton: Locator;
    readonly moreLocationsButton: Locator;
    readonly selectAShopOptions: Locator;
    readonly yourSafeliteShop: Locator;

    readonly firstAvailableDate: Locator;
    readonly firstAvailableTime: Locator;
    readonly modalContinueButton: Locator;
    readonly dropOffButton: Locator;
    readonly dateText: Locator;
    readonly viewMoreDatesLink: Locator;
    readonly appointmentDuration: Locator;
    readonly timeSlots: Locator;
    readonly allDayDropOffButton: Locator;
    readonly pickATimeButton: Locator;

    constructor(page: Page) {
        super(page);
        this.page = page;
        
        this.inShopButton = this.page.locator('label[buttonlabel="You come to our store"]');
        this.mobileButton = this.page.locator('label[buttonlabel="Our mobile shop comes to you"]');
        this.RecalWarningMessage1 = this.page.getByText(/We're not able to provide mobile service/);
        this.RecalWarningMessage2 = this.page.getByText(/advanced safety system recalibration needs to be done in our shop./);
        this.militaryWarningMessage = this.page.locator('[class*="widget-name-AlertMilitaryBaseZipWidget"]');
        this.changeZipButton = this.page.locator('a:has(span.sr-only:has-text("edit zip code"))');
        this.updateZipTextBox = this.page.locator('#serviceZipCode').filter({ visible: true });
        this.safeliteShopsList = this.page.locator('fieldset:has(#chooseShop) label');
        this.searchButton = this.page.locator('.search-icon-button');
        this.storeAddressText = this.page.locator('#shop-location label:not(:first-child)');
        this.saveLocationButton = this.page.getByText('Save location', { exact: true });
        this.moreLocationsButton = this.page.locator(".shop-question a").filter({ hasText: "More locations " });
        this.selectAShopOptions = this.page.locator('[class="shop-question"]');
        this.yourSafeliteShop = this.page.locator("fieldset:has(#chooseShop) label");

        this.allDayDropOffButton = this.page.locator("label[buttonlabel*='Drop']");
        this.pickATimeButton = this.page.locator("label[buttonlabel='Pick a time']");
        this.firstAvailableDate = this.page.locator('.selectable-day').filter({ visible: true}).locator('nth=0');
        this.firstAvailableTime = this.page.locator('label').filter({ hasText: /AM|PM/ }).locator('div').locator('nth=0');
        this.modalContinueButton = this.page.getByRole('dialog').getByRole('button', { name: 'Continue' });
        this.dropOffButton = this.page.getByText('Drop off your vehicle', { exact: true });
        this.dateText = this.page.locator('label.modal-title');
        this.viewMoreDatesLink = this.page.getByText(/View more dates/).first();
        this.appointmentDuration = this.page.locator('.duration-text-block');
        this.timeSlots = this.page.locator('fieldset:has(>legend#chooseTimeSlot) label').filter({ visible: true});
    }

    async selectLocation(testData: Partial<ITestData>) {
        const { appointmentDetails, customerDetails } = testData;
    
        switch(appointmentDetails?.serviceLocation) {
            case ServiceLocation.Mobile:
                await this.scheduleMobile(testData);
                break;
            case ServiceLocation.InShop:
            case ServiceLocation.DropOff:
                await this.scheduleInShop(appointmentDetails);
                break;
        }
    }

    async scheduleInShop(appointmentDetails?: IAppointmentDetails) {

        await this.inShopButton.isVisible() ? await this.inShopButton.click() : null;
        if (appointmentDetails && appointmentDetails.shopAddress) {
            const zipCodeMatch = appointmentDetails.shopAddress.match(/\b\d{5}$/);
            if (zipCodeMatch) {
                const zipCode = zipCodeMatch[0];
                // Enter the ZIP code into the updateZipTextBox
                await this.moreLocationsButton.click();
                await this.page.waitForTimeout(500);
                await this.updateZipTextBox.fill(zipCode);
                await this.searchButton.click().then( async() => await this.page.locator('loader-wrapper').waitFor({state: 'hidden'}));
                await this.safeliteShopsList.first().click();
                // Click the save location button
                await this.saveLocationButton.click();
            }

            // await this.inShopButton.click();
            // await this.selectAShopOptions.locator(`[buttonbodycopy="${appointmentDetails.shopAddress}"]`).scrollIntoViewIfNeeded().then(() => this.selectAShopOptions.locator(`[buttonbodycopy="${appointmentDetails.shopAddress}"]`).click());
        }

        if (appointmentDetails && (appointmentDetails.shopAddress === "" || appointmentDetails.shopAddress === undefined )) {
            appointmentDetails.shopAddress = '';
            await this.storeAddressText.first().waitFor({ state: 'visible' });
            const elements = await this.storeAddressText.all();
            
            for (let element of elements) {
                let addressLine = await element.textContent() || "";
                appointmentDetails.shopAddress += addressLine + ", "
            };
            appointmentDetails.shopAddress = appointmentDetails.shopAddress?.slice(0, -2);
        }
    }

    async scheduleMobile(testData: Partial<ITestData>) {
        const { appointmentDetails, customerDetails } = testData;
        if (appointmentDetails?.serviceAddress) {
            await this.mobileButton.click();
        }
    }

    async scheduleAppointment(appointmentDetails: IAppointmentDetails) {
        const formattedDate = formatDate(appointmentDetails.appointmentDate!);
        const formattedTime = formatTime(appointmentDetails.appointmentDate!);
        const dateInput = this.page.locator(`div[id="${formattedDate}"]`);
        const timeButton = this.page.locator(`div[aria-label="${formattedTime}"]`);
        if (await dateInput.isVisible()) {
            await dateInput.click();
        } else {
            await this.viewMoreDatesLink.click();
            await dateInput.click();
        }
        await timeButton.click();
        await this.modalContinueButton.click();
    }

    async scheduleFirstAppointment(testData: Partial<ITestData>) {
        const { appointmentDetails, customerDetails } = testData;
        // await this.page.waitForTimeout(1000);
        await this.page.waitForSelector('.date-picker', { state: 'visible' });
        await this.page.locator('#date-picker-fieldset .loader').filter({visible: true}).waitFor({ state: 'hidden' });
        while (!(await this.firstAvailableDate.isVisible())) {

            if (appointmentDetails?.appointmentTimeSlot === AppointmentTimeslot.EarlyBird) {
                await this.mockScheduleResponseForEarlyBird(customerDetails!);
            }
            await this.viewMoreDatesLink.click();
        }

        switch(appointmentDetails?.serviceLocation) {
            case ServiceLocation.InShop:
                await this.firstAvailableDate.click().then(async () => {
                    customerDetails!.apptDate = `${await this.firstAvailableDate.getAttribute("id")}`
                });
                if (await this.pickATimeButton.isVisible()) {
                    await this.pickATimeButton.click();
                }
                break;
            case  ServiceLocation.DropOff:
                const inshopAvailableDates = this.page.locator('.selectable-day').filter({ visible: true}).all();
                    for (const inshopAvailableDate of await inshopAvailableDates) {
                        await inshopAvailableDate.click();
                        await this.page.waitForTimeout(500);
                        if (await this.allDayDropOffButton.isVisible()) {
                            customerDetails!.apptDate = `${await inshopAvailableDate.getAttribute("id")}`;
                            break;
                        }
                    }
                break;
            case ServiceLocation.Mobile:
                if (appointmentDetails?.appointmentTimeSlot === AppointmentTimeslot.EarlyBird) {
                    await this.page.locator(`.selectable-days, [id='${customerDetails?.apptDate}-mobile']`).click();
                } else {
                    await this.firstAvailableDate.click().then(async () => {
                        customerDetails!.apptDate = `${await this.firstAvailableDate.getAttribute("id")}`.replace("-mobile", "");
                    });
                }
            break;
        }

        if (appointmentDetails?.appointmentTimeSlot == AppointmentTimeslot.EarlyBird) {
            const earlyBirdTimeSlot = this.timeSlots.filter({ hasText: "Earlybird" }).first();
            await earlyBirdTimeSlot.click().then(async () => {
                customerDetails!.apptTime = await this.getFormattedTimeSlot(earlyBirdTimeSlot);
            })
        } 
        else if (appointmentDetails?.serviceLocation == ServiceLocation.DropOff) 
        {
            await this.allDayDropOffButton.click().then(async () => {
                customerDetails!.apptTime = await this.getFormattedTimeSlot(this.allDayDropOffButton);
            });
        }
        else {
            // const timeSlots = this.timeSlots;
            const timeSlotCount = await this.timeSlots.count();
            const randomIndex = Math.floor(Math.random() * timeSlotCount);
            const timeSlot = this.timeSlots.nth(randomIndex);
            await timeSlot.click().then(async () => {
                customerDetails!.apptTime = await this.getFormattedTimeSlot(timeSlot);
            });
        }

        // appointmentmentDetails.serviceLocation === ServiceLocation.DropOff ? await this.dropOffButton.click() : await this.firstAvailableTime.click();
        customerDetails!.apptDuration = (await this.appointmentDuration.innerText()).replace("Your service will take approximately ", "").replace("Duration: ", "");
    }

    async getFormattedTimeSlot(timeSlot: Locator) {  
        const selectedTimeSlot = await timeSlot.innerText();
        let formattedTimeSlot: string = "";
        if (selectedTimeSlot.toLowerCase().includes("drop"))
        {
            formattedTimeSlot = selectedTimeSlot.includes("overnight") ? "drop off by 5:30 pm on the night of your scheduled appointment. Pick-up time dependent on shop schedule" : "before 9:30 AM" // "drop off before 9:30 AM";
        }
        else if (selectedTimeSlot.includes("-") || selectedTimeSlot.includes("Earlybird")) // - means Mobile time slot where service time is between 8:00 AM - 12:00 PM
        {
            formattedTimeSlot = selectedTimeSlot.includes("Earlybird") ? "arriving between 8:00 AM - 12:00 PM" : `arriving between ${selectedTimeSlot}`;
        }
        else
        {
            formattedTimeSlot = `at ${selectedTimeSlot}`;
        }    
        return formattedTimeSlot;
    }

    @step("SchedulePage >> Schedule appointment: ")
    async handleSchedulePage(testData: Partial<ITestData>) {
        const { appointmentDetails } = testData;
        await this.validateProgressBar(ProgressBarPercentages.SchedulePage);
        await this.selectLocation(testData);
        await this.scheduleFirstAppointment(testData);
        await this.nextPage();
    }
}
