import test, { expect, type Locator, type Page } from '@playwright/test';
import { BasePage } from './BasePage';
import { ICustomerDetails, IVehicleDetails } from '@business-logic/types/CustomerDetails';
import { PaymentType, ServicePackage } from '@business-logic/types/Enums';
import { ITestData } from '@business-logic/types/ITestData';

export class OrderConfirmationPage extends BasePage {
    readonly page: Page;

    readonly successCheckmark: Locator;
    readonly successHeader: Locator;

    readonly serviceText: Locator;
    readonly workOrderNumberText: Locator;
    readonly confirmationText: Locator;
    readonly appointmentTypeText: Locator;
    readonly apptDetailsText: Locator;
    readonly deductibleText: Locator;
    readonly subtotalText: Locator;
    readonly totalAmountDueText: Locator;
    readonly amountPaidText: Locator;
    readonly finalAmountDue: Locator;
    readonly cartLineItemsText: Locator;
    readonly unverifiedCoverageDeductibleText: Locator;

    issPageValue = 'order-confirmation';

    constructor(page: Page) {
        super(page);
        this.page = page;
 
        this.successCheckmark = this.page.locator('img[src*="-checkmark.svg"]');
        this.successHeader = this.page.locator('[class="header-text"]');

        this.confirmationText = this.page.locator('[class="subheader-text"]', { hasText: 'Your appointment is on Safelite\'s schedule and your confirmation email is on the way.' });
        this.serviceText = this.page.locator('[class="service-description confirmation-section"]');
        this.workOrderNumberText = this.page.locator('[class="work-order-description"]');
        this.appointmentTypeText = this.page.locator('[class="appointment-title"]');
        this.apptDetailsText = this.page.locator('[class="appointment-details confirmation-section"]');

        // Order details section
        this.deductibleText = this.page.locator('span#deductible-value, span.deductible-value');
        this.subtotalText = this.page.locator('#subtotal-value');
        this.totalAmountDueText = this.page.locator('#total-value');
        this.amountPaidText = this.page.locator('#amount-paid-value');
        this.finalAmountDue = this.page.locator('#bottom-amount-due-value');
        this.cartLineItemsText = this.page.locator('.cart-item-list');
        this.unverifiedCoverageDeductibleText = this.page.locator('span#deductible-value', { hasText: 'Verifying coverage' });
    }

    async validateOrderConfirmationPage(testData: Partial<ITestData>) {
        // Destructure data we use
        const { vehicleDetails, customerDetails, servicePackage, isItac,
            isNoComp, isPolicyFound, claimDetails, paymentDetails, isUseVehicleOnPolicy } = testData;


        // Grab text
        const serviceTextValue = await this.serviceText.textContent();
        const apptDetailsValue = await this.apptDetailsText.textContent();
        const appointmentTypeValue = await this.appointmentTypeText.textContent();


        // Derived conditions
        const isItacOrNoComp = !!(isItac || isNoComp);
        const isUnverified = !isPolicyFound;
        const isUnverifiedPolicyAfterVehicleLookup = testData.isUnverifiedPolicyAfterVehicleLookup === true;
        const hasPremiumOrStandard =
            (claimDetails!.policyDeductible >= 0 || !isPolicyFound) &&
            (servicePackage === ServicePackage.Premium || servicePackage === ServicePackage.Standard);

        const payAtService =
            (claimDetails!.policyDeductible >= 0 &&
            paymentDetails?.paymentType === PaymentType.PayAtService) || !paymentDetails?.paymentType;

        const paidWithPIA = 
            claimDetails!.policyDeductible >= 0 &&
            paymentDetails?.paymentType !== PaymentType.PayAtService;

        // Helper: grab textContent only when the element is expected on-screen
        const textIf = async (condition: boolean, locator: Locator) =>
            condition ? await locator.textContent() : null;

        // Grab text content for elements that are expected on-screen
        const lineItemsValue = await textIf(hasPremiumOrStandard, this.cartLineItemsText);
        const deductibleTextValue  = await textIf(!isItacOrNoComp, this.deductibleText);
        const subtotalTextValue    = await textIf((hasPremiumOrStandard || isItacOrNoComp) && !isUnverified && !isUnverifiedPolicyAfterVehicleLookup, this.subtotalText);
        const totalAmountDueValue  = await textIf((hasPremiumOrStandard && !payAtService) || (isItacOrNoComp && !payAtService) && !isUnverified && !isUnverifiedPolicyAfterVehicleLookup, this.totalAmountDueText);
        const amountPaidTextValue  = await textIf((hasPremiumOrStandard && !payAtService) || (isItacOrNoComp && !payAtService) && !isUnverified && !isUnverifiedPolicyAfterVehicleLookup, this.totalAmountDueText);
        const finalAmountDueValue  = await textIf(hasPremiumOrStandard || isItacOrNoComp || isUnverified || isUnverifiedPolicyAfterVehicleLookup, this.finalAmountDue);
        const confirmationTextValue = await this.confirmationText.textContent();
    


        // General Validations
        expect.soft(this.serviceText).toBeVisible();;
        expect.soft(this.successHeader).toBeVisible();
        expect.soft(confirmationTextValue).toContain('Your appointment is on Safelite\'s schedule and your confirmation email is on the way.');
        expect.soft(serviceTextValue).toContain(`${vehicleDetails!.year} ${vehicleDetails!.make} ${vehicleDetails!.model}`);

        // Validate order number and appointment type header
        await this.validateOrderNumber();
        await this.validateAppointmentTypeHeader();

        // Validate line items
       if (servicePackage === ServicePackage.Premium) {
            expect.soft(lineItemsValue).toContain('Front advanced beam blades');
            expect.soft(lineItemsValue).toContain('Safelite Rain Repellent Treatment');
        } else { 
            if (servicePackage === ServicePackage.Standard) {
            expect.soft(lineItemsValue).toContain('Front advanced beam blades');
            }
        } 


        if (isPolicyFound && (claimDetails!.policyDeductible === 0 && (servicePackage === ServicePackage.GlassOnly))) {
            const zeroDeductibleText = await this.deductibleText.textContent();
            expect.soft(zeroDeductibleText).toEqual('$0.00');
        } else if (isPolicyFound && claimDetails!.policyDeductible > 0 && !(isItac || isNoComp) && servicePackage === ServicePackage.GlassOnly){
            expect.soft(deductibleTextValue).not.toBeNull();
            const deductibleAmt = deductibleTextValue ? Number.parseFloat(deductibleTextValue.split('$')[1].replaceAll(',', '')) : 0;
            expect.soft(deductibleAmt).toEqual(claimDetails!.policyDeductible);
            
        } else if ((isPolicyFound || isItac || (isNoComp && paymentDetails!.paymentType === PaymentType.PayAtService)) && !isUnverifiedPolicyAfterVehicleLookup && finalAmountDueValue !== null && subtotalTextValue !== null) {
            // Extract numbers
            const deductibleAmt = deductibleTextValue ? Number.parseFloat(deductibleTextValue.split('$')[1].replaceAll(',', '')) : null;

            const subtotalAmt = subtotalTextValue ? Number.parseFloat(subtotalTextValue!.split('$')[1].replaceAll(',', '')) : null;


            //const totalAmountDueAmt = Number.parseFloat(totalAmountDueValue!.split('$')[1].replaceAll(',', ''));
            const finalAmountDueAmt = finalAmountDueValue ? Number.parseFloat(finalAmountDueValue!.split('$')[1].replaceAll(',', '')) : null;

            if (!(isItac || isNoComp)) {
                expect.soft(deductibleAmt).toEqual(claimDetails!.policyDeductible);
            } else {
                expect.soft(subtotalAmt).toBeGreaterThan(0);
                //expect.soft(deductibleAmt).toEqual(0);
            }

            if ((paymentDetails!.paymentType === PaymentType.PayAtService) && (claimDetails!.policyDeductible >= 0 && (servicePackage === ServicePackage.Standard || servicePackage === ServicePackage.Premium))) {
                expect.soft(finalAmountDueAmt).toBeGreaterThan(0);
            } else {
                const totalAmountDueAmt = Number.parseFloat(totalAmountDueValue!.split('$')[1].replaceAll(',', ''));
                const amountPaidValue = Number.parseFloat(amountPaidTextValue!.split('$')[1].replaceAll(',', ''));
                // Verify amount due 0 usually when PIA is selected
                expect.soft(amountPaidValue).toEqual(totalAmountDueAmt);                
                expect.soft(finalAmountDueAmt).toEqual(0);
            }
        } else {
            // essential flows will have deductible and amount due as "Verifying coverage"
            const verifyingCoverageText = this.unverifiedCoverageDeductibleText;
            
            expect.soft(verifyingCoverageText).toContainText('Verifying coverage');
            expect.soft(finalAmountDueValue).toEqual('Verifying coverage');
        }
    }

    async validateOrderNumber() {
        const sessionStorage = JSON.parse(await this.page.evaluate('sessionStorage.getItem(\'submittedOrder\')'));
        const workOrderNumber = sessionStorage.workOrderNumber;
        const workOrderNumberValue = await this.workOrderNumberText.textContent();
        expect.soft(workOrderNumberValue).toEqual(workOrderNumber);
    }

    async validateAppointmentTypeHeader() {
        const sessionStorage = JSON.parse(await this.page.evaluate('sessionStorage.getItem(\'submittedOrder\')'));
        const appointmentType = sessionStorage.serviceLocation.appointmentType;
        const appointmentTypeValue = await this.appointmentTypeText.textContent();
        const apptDetailsValue = await this.apptDetailsText.textContent();
        
        if (appointmentTypeValue?.includes('going to a Safelite shop') && apptDetailsValue?.includes('Drop off before 9:30 AM'))  {
            expect.soft(appointmentType).toEqual('Dropoff');
        } else if (appointmentTypeValue?.includes('going to a Safelite shop')) {
            expect.soft(appointmentType).toEqual('Inshop');
        } else {
            expect.soft(appointmentType).toEqual('Mobile');
        }
    }
    
    async validateURL() {
        let pass = false;
        let currentUrl = this.page.url();
        pass = currentUrl.includes(this.issPageValue);
        while(!pass && currentUrl.includes('payment')) {
            await this.waitForURLToChange(currentUrl);
            currentUrl = this.page.url();
            pass = currentUrl.includes(this.issPageValue);
        }
        const isBailout = currentUrl.includes('bailout-page');
        if(!pass && !isBailout) {
            await this.waitForURLToChange(currentUrl);
            currentUrl = this.page.url();
        }
        expect(currentUrl).toContain(this.issPageValue);
    }
}