import { expect, type Locator, type Page } from '@playwright/test';
import { BasePage } from './BasePage';
import { IPaymentDetails } from '@business-logic/types/CustomerDetails';
import { PaymentMethod, PaymentType, ServicePackage, VehicleDamage } from '@business-logic/types/Enums';
import { PaymentPage } from './PaymentPage';
import { AfterpayPage } from './AfterpayPage';
import { PaypalPage } from './PaypalPage';
import { ITestData } from '@business-logic/types/ITestData';

export class PaymentMethodPage extends BasePage {
    readonly page: Page;
    readonly payAtServiceButton: Locator;
    // readonly paypalButton: Locator;
    // readonly creditCardButton: Locator;
    readonly payNowButton: Locator;
    readonly payWithInsuranceButton: Locator;
    readonly payInFourButton: Locator;
    readonly amountDueTextField: Locator;
    readonly amountDueDropDown: Locator;
    readonly appointmentDetailsDropdown: Locator;
    readonly subtotalAmountTextField: Locator;
    readonly submitButton: Locator;
    readonly recalibrationCheckbox: Locator;
    readonly paymentPage: PaymentPage;
    readonly paypalPage: PaypalPage;

    // Payment detail page validation locators
    readonly reviewTable: Locator;
    readonly vehicleSection: Locator;
    readonly damageSection: Locator;
    readonly serviceDetailsSection: Locator;
    readonly serviceLocationSection: Locator;
    readonly appointmentDateSection: Locator;
    readonly contactDetailsSection: Locator;
    readonly cartPanelDetails: Locator;
    readonly subtotalText: Locator;
    readonly finalAmountDueText: Locator;
    readonly glassServiceText: Locator;
    readonly wiperBladesText: Locator;
    readonly rainDefenseText: Locator;
    readonly deductibleText: Locator;

    url = process.env['BASE_URL']! + '/fmg/?fmgPage=payment-method';

    constructor(page: Page) {
        super(page);
        this.page = page;
        this.payAtServiceButton = this.page.locator('[buttonlabel="Pay at my appointment"]'); //this.page.getByText('Pay at time of service');
        this.amountDueTextField = this.page.getByLabel('expand cart').locator('.amount-due');
        this.amountDueDropDown = this.page.getByLabel('expand cart');
        this.appointmentDetailsDropdown = this.page.getByLabel('expand appointment details');
        this.payWithInsuranceButton = this.page.locator('div').filter({ hasText: /^Pay with insurance$/ }).nth(1);
        this.subtotalAmountTextField = this.page.locator('.sub-total span').nth(1);
        this.payNowButton = this.page.locator('[buttonlabel="Pay now"]');
        this.payInFourButton = this.page.locator('[buttonlabel="Pay in 4 installments"]');
        this.submitButton = this.page.locator('[data-test-id="nav-bar-main-button"]');
        this.recalibrationCheckbox = this.page.getByLabel('I understand after windshield');
        // this.creditCardButton = page.locator('div').filter({ hasText: /^Credit or Debit$/ }).nth(1);
        this.paymentPage = new PaymentPage(page);
        this.paypalPage = new PaypalPage(page);

        // Payment details validation locators
        this.reviewTable = this.page.locator('div.review-table');
        
        // Section locators - find by heading text
        this.vehicleSection = this.page.locator('.review-table').locator('div', { hasText: 'Vehicle' }).first();
        this.damageSection = this.page.locator('.review-table').locator('div', { hasText: 'Damage' }).first();
        this.serviceDetailsSection = this.page.locator('.review-table').locator('div', { hasText: 'Glass service only' }).first();
        this.serviceLocationSection = this.page.locator('.review-table').locator('div', { hasText: "We're coming to you" }).first();
        this.appointmentDateSection = this.page.locator('.review-table').locator('div', { hasText: 'Appointment date + time' }).first();
        this.contactDetailsSection = this.page.locator('.review-table').locator('div', { hasText: 'Contact details' }).first();
        
        // Cart panel elements
        this.cartPanelDetails = this.page.locator('.cart-panel');
        this.subtotalText = this.page.locator('.sub-total');
        this.finalAmountDueText = this.page.locator('div.amount-due');
        this.glassServiceText = this.page.locator('div', { hasText: /^Glass service only$/ });
        this.wiperBladesText = this.page.locator('div', { hasText: /^New wiper blades$/ });
        this.rainDefenseText = this.page.locator('div', { hasText: /^Rain Defense™$/ });
        this.deductibleText = this.page.locator('#deductible-value');
    }

    async validatePaymentDetailsPage(testData: Partial<ITestData>) {
        // Destructure data we use
        const { vehicleDetails, customerDetails, servicePackage, promoCode,
            isPolicyFound, claimDetails, paymentDetails, appointmentDetails,
            isUseVehicleOnPolicy, paymentMethod, vehicleDamage } = testData;

        // Wait for review table to be visible to ensure page is loaded
        await this.appointmentDetailsDropdown.waitFor({state: "visible"});
        await this.appointmentDetailsDropdown.click(); // Expand cart to see all details
        await this.amountDueDropDown.click();
        await this.reviewTable.waitFor({ state: "visible" });

        // Helper method to get content lines from a section
        const getSectionContent = async (section: Locator) => {
            // First make sure section exists
            if (await section.count() === 0) return [];
            
            // Find all content lines within this section
            const contentLines = await section.locator('div.small.review-block-content').allInnerTexts();
            return contentLines;
        };

        // Validate vehicle information
        const vehicleContent = await getSectionContent(this.vehicleSection);
        if (vehicleContent.length > 0) {
            const vehicleText = vehicleContent[0];
            expect.soft(vehicleText).toContain(`${vehicleDetails?.year} ${vehicleDetails?.make} ${vehicleDetails?.model}`);
        }

        // Validate damage type

        // TODO: Work out logic on how to verify vehicle Damage in payment details with vehicleDamage

        // const damageContent = await getSectionContent(this.damageSection);
        // if (vehicleDamage && damageContent.length > 0) {
        //     const damageText = damageContent[0];
    
        //     // For each damage type in the array, check if its display text is in the damage content
        //     for (const damage of vehicleDamage) {
        //         const expectedDamageText = this.getDamageDisplayText(damage);
        
        //         // If this is a single damage item, it should match exactly
        //         if (vehicleDamage.length === 1) {
        //             expect.soft(damageText).toContain(expectedDamageText);
        //         } else {
        //             // For multiple damages, check if any of the damage content lines contain this damage type
        //             const damageFound = damageContent.some(content => 
        //                 content.includes(expectedDamageText)
        //             );
        //             expect.soft(damageFound).toBeTruthy();
        //         }
        //     }
        // }

        // Validate service details based on package
        const serviceContent = await getSectionContent(this.serviceDetailsSection);
        if (servicePackage && serviceContent.length > 0) {
            //TODO: Add service package validation
            // move over logic from Kishan's code
            
            // Additional validations for Standard and Premium packages
            if (servicePackage === ServicePackage.Premium || servicePackage === ServicePackage.Standard) {
                await expect.soft(this.wiperBladesText).toBeVisible();
            }
            
            if (servicePackage === ServicePackage.Premium) {
                await expect.soft(this.rainDefenseText).toBeVisible();
            }
        }

        // Validate service location
        const locationContent = await getSectionContent(this.serviceLocationSection);
        if (appointmentDetails?.serviceLocation && locationContent.length > 0) {
            // Find the title element of the service location section
            const serviceLocationTitle = this.serviceLocationSection.locator('span').first();
            const serviceLocationValue = await serviceLocationTitle.innerText();
            
            // Check for mobile/inshop service wording
            if (appointmentDetails.serviceLocation.toString().includes('Mobile')) {
                expect.soft(serviceLocationValue).toContain("We're coming to you");
            } else if (appointmentDetails.serviceLocation.toString().includes('InShop')) {
                expect.soft(serviceLocationValue).toContain("Bring to shop");
            }
            
            // Validate address if available
            if (appointmentDetails.serviceAddress && locationContent.length > 0) {
                const addressText = locationContent[0].toLowerCase();
                expect.soft(addressText).toContain(appointmentDetails.serviceAddress.street.toLowerCase());
            }
        }

        // Validate appointment date/time
        const appointmentContent = await getSectionContent(this.appointmentDateSection);
        if (customerDetails?.apptDate && appointmentContent.length > 0) {
            const appointmentText = appointmentContent[0];
            expect.soft(appointmentText).toContain(customerDetails.apptDate);
        }

        // Validate contact details
        const contactContent = await getSectionContent(this.contactDetailsSection);
        if (customerDetails && contactContent.length > 0) {
            const fullName = `${customerDetails.firstName} ${customerDetails.lastName}`;
            const email = customerDetails.email;
            const phone = customerDetails.phoneNumber;
            
            // Check if contact details are present
            const contactTextJoined = contactContent.join(' ');
            expect.soft(contactTextJoined).toContain(fullName);
            expect.soft(contactTextJoined).toContain(email);
            expect.soft(contactTextJoined).toContain(phone);
        }

        // Cart Validation
        // Get pricing information from cart panel
        if (await this.subtotalText.isVisible()) {
            const subtotalValue = await this.subtotalText.innerText();
            const finalAmountDueValue = await this.finalAmountDueText.innerText();

            // Pricing validations differ by payment method
            if (paymentMethod === PaymentMethod.SelfPay && paymentDetails?.paymentType !== PaymentType.PayWithInsurance) {
                // Extract amounts for self-pay customers
                const subtotalAmount = this.extractAmount(subtotalValue);
                const finalAmountDueAmount = this.extractAmount(finalAmountDueValue);
                
                // Subtotal should be greater than 0
                expect.soft(subtotalAmount).toBeGreaterThan(0);
                
                // Final amount differs based on payment type
                if (paymentDetails?.paymentType === PaymentType.PayAtService) {
                    expect.soft(finalAmountDueAmount).toBeGreaterThan(0);
                } else if (paymentDetails?.paymentType === PaymentType.Credit ||
                          paymentDetails?.paymentType === PaymentType.Paypal ||
                          paymentDetails?.paymentType === PaymentType.AfterPay) {
                    // For payment types that charge immediately, amount due could be 0
                    // This logic might need adjusting based on actual business rules
                }
            } else {
                // For insurance payments, check for proper indicators
                // TODO: Apply logic for deductible and insurance payment logic
            }

            // Service package validations
            const servicePackageValue = await this.cartPanelDetails.textContent();
            await expect.soft(this.cartPanelDetails).toContainText(`${servicePackage}`)
            if (servicePackage === ServicePackage.Premium || servicePackage === ServicePackage.Standard) {
                expect.soft(servicePackageValue).toContain('New wiper blades');
            }
            if (servicePackage === ServicePackage.Premium) {
                expect.soft(servicePackageValue).toContain('Rain Defense™');
            }

            // Promo Code Validation
            if (promoCode) {
                expect.soft(servicePackageValue).toContain(`Promo code ${promoCode} applied`);
            };
        }
    }

    /**
     * Helper method to extract numeric amount from price strings like "$123.45"
     */
    private extractAmount(valueString: string): number {
        const matches = valueString.match(/\$([0-9,]+(\.[0-9]{2})?)/);
        if (matches && matches[1]) {
            return parseFloat(matches[1].replace(/,/g, ''));
        }
        return 0;
    }

    async getAmountDue(): Promise<string> {
        await expect(this.amountDueTextField).toBeVisible();
        const text = await this.amountDueTextField.textContent();
        if (!text) throw new Error("Amount due text is empty");
        return text;
    }

    async getSubtotal(): Promise<string> {
        await this.amountDueDropDown.click();
        await expect(this.subtotalAmountTextField).toBeVisible();
        const text = await this.subtotalAmountTextField.textContent();
        if (!text) throw new Error("Subtotal text is empty");
        return text;
    }
    
    async executePayment(paymentDetails: IPaymentDetails, isRecalVehicle: boolean) {
        const browserContext = this.page.context();

        switch(paymentDetails.paymentType) {
            case PaymentType.Credit:
                await this.selectCreditCard();
                await this.nextPage();
                await this.paymentPage.populateCreditCardDetails(paymentDetails);
                await this.nextPage();
                break;
            case PaymentType.AfterPay:
                await this.payInFourButton.click();
                await this.nextPage();

                // Capture popup
                const afterpayPopup = await browserContext.waitForEvent('page');
                const afterpayPage = new AfterpayPage(afterpayPopup);

                // Execute payment
                await afterpayPage.executeAfterpayPayment(paymentDetails);
                break;
            case PaymentType.Paypal:
                await this.selectPaypal();
                // TODO: Click paypal button
                await this.nextPage();
                await this.paymentPage.navigateToPaypalCheckout();
                await this.paypalPage.completePaypalPurchase(paymentDetails);
                break;
            case PaymentType.PayAtService:
                await this.selectPayAtService(isRecalVehicle);
                await this.nextPage();
                break;
            case PaymentType.PayWithInsurance:
                await this.payWithInsuranceButton.click();
                await this.nextPage();
                break;
            default:
                console.error('PaymentMethodPage >> Logic for this payment method unimplemented');
                break;
        }
    }

    async selectPaypal(){
        await this.payNowButton.click();
    }
l
    async selectCreditCard(){
        await this.payNowButton.click();
    }

    async selectPayAtService(isRecalVehicle: boolean){
        if (await this.payAtServiceButton.isVisible()) {
            await this.payAtServiceButton.click();
        } else if (isRecalVehicle) {
            await this.recalibrationCheckbox.click();
        }

    }

    async verifyVAPS(): Promise<void> {
        // Get Vuex state from localStorage
        const vuexState = JSON.parse(await this.page.evaluate('localStorage.getItem(\'vuex\')'));
    
        // Validate the count of FRONT WIPER parts
        if (vuexState.order?.lineItems?.vaps?.length > 0) {
            const frontWiperPartsCount = vuexState.order.lineItems.vaps.filter(vap =>
                vap.partType === "FRONT WIPER"
            ).length;
    
            await expect(frontWiperPartsCount).toBe(2);
        } else {
            throw new Error("No VAPS found in the order");
        }
    }

}