<template>
    <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
        <loadingModal ref="loadingModal" />
        <div
            class="container-fluid page-container-grouped-styles quote-page"
            :class="showSaveProgressPopup ? 'show-save-progress-popup' : ''">
            <div class="row justify-content-center funnel-header-wrapper">
                <div class="col-md-6">
                    <funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
                </div>
            </div>
            <div class="row justify-content-center">
                <div class="col-md-6 col-xl-4 mt-4">
                    <funnelSubHeader class="mb-5" cmsWidgetName="FunnelSubHeaderWidget" />
                    <cashOrInsuranceQuestion
                        ref="cashOrInsurance"
                        cmsWidgetName="CashOrInsuranceQuestionWidget"
                        v-model="isInsuranceSelected"
                        groupName="CashOrInsuranceQuestion" />
                </div>
            </div>
            <div class="row justify-content-center">
                <div class="col-md-12 mb-5" :class="getColCount()">
                    <servicePackageQuestion
                        ref="servicePackage"
                        cashCmsWidgetName="CashServicePackageQuestionWidget"
                        insuranceCmsWidgetName="InsuranceServicePackageQuestionWidget"
                        groupName="ServicePackageQuestion"
                        :availableLineItems="availableLineItems"
                        :isInsuranceSelected="isInsuranceSelected"
                        :isRecalibrationOnOrder="isRecalibrationOnOrder"
                        :shouldHideRecalibration="shouldHideRecalibration"
                        @vapsItemsSelected="vapsItemsSelectedAction"
                        @servicePackageDiscountSelected="servicePackageDiscountSelectedAction"
                        @currentNumberOfPackages="currentNumberOfPackagesAction"
                        :servicePackage="servicePackage"
                        :activePromos="lineItems.promos"
                        v-on="{ 'buttonEvent.openModal': openModalAction }"
                        validationRules="option-required"
                        isRequired />
                </div>
            </div>
            <div class="row justify-content-center">
                <div class="col-md-12" :class="getColCount()">
                    <!-- If Cash AND vehicle does not require recal OR if Cash AND State requires showing recal, then show Afterpay banner -->
                    <afterpayModalBanner
                        v-if="showAfterpayBanner"
                        cmsWidgetName="AfterpayModalWidget"
                        :isAfterpayBreakoutDisplay="isAfterpayBreakoutDisplay"
                        :lineItems="lineItems" />

                    <!-- If vehicle requires recal AND we are hiding recal pricing info, then show recal disclaimer banner. -->
                    <recalDisclaimer
                        class="mb-0"
                        cmsWidgetName="RecalDisclaimerWidget"
                        v-if="showRecalDisclaimer"
                        v-on="{ textLinkClicked: openModalAction }"
                        alertClass="alert-info" />

                    <promoModalQuestion
                        class="mt-6 d-flex justify-content-center"
                        v-model="lineItems"
                        :addableVaps="addableVaps"
                        pageName="quote"
                        :taxPromos="false"
                        :useDefaultCashParentAccount="true"
                        modalWidgetName="PromoModalWidget" />
                </div>
            </div>
            <div class="row justify-content-center">
                <div class="col-md-6 col-xl-4">
                    <contentGroupModal ref="RainDefenseModal" cmsWidgetName="RainDefenseModal" />
                    <contentGroupModal ref="FrontWiperModal" cmsWidgetName="FrontWiperModal" />
                    <contentGroupModal ref="RearWiperModal" cmsWidgetName="RearWiperModal" />
                    <contentGroupModal ref="RecalModal" cmsWidgetName="RecalModal" isRecal />

                    <navbar
                        cmsWidgetName="FunnelFooterWidget"
                        :isForwardActionDisabled="!meta.valid"
                        :isBackButtonHidden="shouldHideBackButton"
                        @back-clicked="backButtonAction"
                        @ForwardClicked="forwardButtonAction" />

                    <saveProgressModalQuestion
                        modalWidgetName="SaveProgressModalWidget"
                        modalName="SaveProgressModal"
                        v-if="showSaveProgressModal"
                        pageName="quote" />

                    <textBlock
                        cmsWidgetName="quoteDisclaimer"
                        justifyText="center"
                        typeStyle="caption"
                        class="mb-5 quote-disclaimer" />
                </div>
            </div>

            <div class="row justify-content-center save-progress-popup">
                <div class="col-md-6 col-xl-4">
                    <saveProgressPopupQuestion
                        modalWidgetName="SaveProgressPopupWidget"
                        modalName="SaveProgressPopup"
                        pageName="quote"
                        v-if="showSaveProgressPopup"
                        :showSaveProgressPopup="showSaveProgressPopup"
                        @save-progress-saved="updateSaveProgressAsSaved"
                        @close-save-progress-popup="closeSaveProgressPopup" />
                </div>
            </div>
        </div>
    </Form>
</template>

<script>
// Components
import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import navbar from "@/fmg-components/nav-bar/nav-bar";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import cashOrInsuranceQuestion from "./cash-or-insurance-question/cash-or-insurance-question";
import servicePackageQuestion from "./service-package-question/service-package-question";
import textBlock from "@/digital-components/text-block/text-block";
import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal";
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
import afterpayModalBanner from "@/layouts/quote/afterpay-modal-banner/afterpay-modal-banner";
import recalDisclaimer from "@/layouts/quote/recal-disclaimer/recal-disclaimer.vue";
import saveProgressModalQuestion from "@/fmg-components/save-progress-modal-question/save-progress-modal-question";
import saveProgressPopupQuestion from "@/fmg-components/save-progress-popup-question/save-progress-popup-question";

// Supporting files
import baseMixin from "@/mixins/base-mixin.js";
import experimentMixin from "@/mixins/experiment-mixin.js";
import vehicleQuestionsMixin from "../../mixins/vehicle-questions-mixin";
import { settleAllPromises } from "@/helpers/layout-helper";
import { storeActions } from "@/constants/store-actions";
import { deepClone } from "@/helpers/object-helper";
import store from "@/store";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { experimentSettings, experimentUniverses } from "@/constants/experiments";
import { required } from "@/helpers/validation-rules";
import { errorMessages } from "@/constants/error-messages";
import { Form, defineRule } from "vee-validate";
import { applicationConfig } from "@/constants/application-config";
import { payWithInsuranceStates } from "@/constants/insurance";
import {
    revalidatePromosAndValidateQueryStringPromo,
    buildToastMessagesFromRevalidateOrValidatePromoResponse,
    createPromoSuccessAlert,
} from "@/helpers/promotions-helper";
import { queryStrings } from "@/constants/query-strings";
import { getQuerystringParameter } from "@/helpers/querystring-helper";
import promoModalQuestion from "@/fmg-components/promo-modal-question/promo-modal-question";
import { partTypeStrings } from "@/constants/part-type-strings";
import {
    containsLineItemWithPartType,
    findLineItemsWithPartType,
} from "@/helpers/service-package-helper";
import { nextTick } from "vue";
import { packageNames, externalParamPackageLabels } from "@/constants/package-names";
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
import { containsRecalParts } from "@/helpers/recal-helper";
import { externalParameterStatus } from "@/constants/external-parameters";
import { saveQuote } from "@/helpers/heritage-integration/order-helper.js";
import { getBoolFromString } from "@/helpers/boolean-helper";
import {
    getSessionKeyValue,
    getUserIdValue,
    getDeviceIdValue,
} from "@/helpers/heritage-integration/cookie-helper";
import { showFmgLoadingModal } from "@/helpers/loading-modal-helper";
import { routeData } from "@/router/constants/routes";
import { consumeQueryFromStash } from "@/router/methods/helpers/querystring-stash";
import { storeMutations } from "@/constants/store-mutations";
import { debugLog } from "@/helpers/debug-log-helper";

defineRule("option-required", required(errorMessages.OPTION_REQUIRED));

const INSURANCE_TAB_TO_DISPLAY_THRESHOLD_DEFAULT = 300;

const ACCEPTED_QUOTE_TYPES = {
    CASH: "cash",
    INSURANCE: "insurance",
};

export default {
    name: "quote",
    async beforeRouteEnter(to, from, next) {
        // Call APIs
        const cmsContentPromise = fetchCmsContentForPage(to.name);
        const wipersPromise = baseMixin.methods.dispatchStoreActionWithLogging(
            storeActions.GET_WIPERS,
            {
                serviceZipCode: store.getters.order.serviceLocation.zipCode,
                carId: store.getters.vehicle.carId,
            },
            "quote"
        );
        const rainDefensePromise = baseMixin.methods.dispatchStoreActionWithLogging(
            storeActions.GET_RAIN_DEFENSE,
            null,
            "quote"
        );
        const supportingItemsPromise = baseMixin.methods.dispatchStoreActionWithLogging(
            storeActions.GET_SUPPORTING_ITEMS,
            null,
            "quote"
        );

        const shouldExposeSkipQuote = store.getters.isRecalibrationOnOrder;
        const skipQuoteExperiment = store.getters.applicationUser.experiments.find(
            (e) => e.universeName === experimentUniverses.IGQ_SkipQuote
        );
        const hasExposedSkipQuote = skipQuoteExperiment?.isExposed;

        const shouldSendExposeRequest =
            shouldExposeSkipQuote && !hasExposedSkipQuote && skipQuoteExperiment;

        if (shouldSendExposeRequest) {
            // Don't await -- response is not needed so can fire fully asynchronously.
            baseMixin.methods.dispatchStoreActionWithLogging(
                storeActions.LOG_EXPERIMENT_EXPOSURE_AND_UPDATE_STORE,
                {
                    userId: getUserIdValue(),
                    deviceId: getDeviceIdValue(),
                    sessionKey: getSessionKeyValue(),
                    pageName: to.name,
                    experiment: skipQuoteExperiment,
                },
                "quote",
                false
            );
        }

        // AfterpayBreakoutDisplay Custom Exposure
        const IGQExperiment = store.getters.applicationUser.experiments.find(
            (e) => e.universeName === experimentUniverses.RECAL_PRICE_REMOVAL
        );
        const hasExposedIGQExperiment = IGQExperiment?.isExposed;

        const afterpayBreakoutDisplayExperiment = store.getters.applicationUser.experiments.find(
            (e) => e.universeName === experimentUniverses.AFTERPAY_BREAKOUT_DISPLAY
        );
        const hasExposedAfterpayBreakoutDisplay = afterpayBreakoutDisplayExperiment?.isExposed;
        const shouldSendAfterpayBreakoutDisplayExposeRequest =
            afterpayBreakoutDisplayExperiment &&
            !hasExposedAfterpayBreakoutDisplay &&
            !hasExposedIGQExperiment;

        if (shouldSendAfterpayBreakoutDisplayExposeRequest) {
            baseMixin.methods.dispatchStoreActionWithLogging(
                storeActions.LOG_EXPERIMENT_EXPOSURE_AND_UPDATE_STORE,
                {
                    userId: getUserIdValue(),
                    deviceId: getDeviceIdValue(),
                    sessionKey: getSessionKeyValue(),
                    pageName: to.name,
                    experiment: afterpayBreakoutDisplayExperiment,
                },
                "quote",
                false
            );
        }

        const promiseResultMap = [
            {
                resultKey: "cmsContent",
                promise: cmsContentPromise,
            },
            {
                resultKey: "wipers",
                promise: wipersPromise,
            },
            {
                resultKey: "rainDefense",
                promise: rainDefensePromise,
            },
            {
                resultKey: "supportingItems",
                promise: supportingItemsPromise,
            },
        ];

        const resultMap = await settleAllPromises(promiseResultMap);
        const emailFromStore = store.getters.order.customer.emailAddress;
        const isEmailInStoreOnPageLoad = emailFromStore?.length > 0;
        const isPopupSkipped =
            store.getters.pageData(routeData.QUOTE.name)?.saveProgressPopupSkipped === true;
        const showSaveProgressPopup = !(isEmailInStoreOnPageLoad || isPopupSkipped);
        const showSaveProgressModal = isEmailInStoreOnPageLoad ? false : true;
        const shouldSkipToInsurance =
            getBoolFromString(
                experimentMixin.methods.getSettingValue(experimentSettings.SKIP_TO_INSURANCE)
            ) &&
            shouldExposeSkipQuote &&
            !hasExposedSkipQuote;

        const lineItems = deepClone(store.getters.order.lineItems);
        lineItems.vaps = lineItems.vaps ?? [];
        const nullSafeGlassParts = lineItems.glassParts ?? [];
        const servicePackageDiscountSettingValue = experimentMixin.methods.getSettingValue(
            experimentSettings.SERVICE_PACKAGE_DISCOUNT
        );
        const isServicePackageDiscount = servicePackageDiscountSettingValue === "True";
        //Service package cash discount api call when experiment is active
        var servicePackageDiscountPart = [];
        if (isServicePackageDiscount) {
            const servicePackageDiscountPartResponse =
                await baseMixin.methods.dispatchStoreActionWithLogging(
                    storeActions.GET_SERVICE_PACKAGE_DISCOUNT_PART,
                    null,
                    "quote"
                );
            if (servicePackageDiscountPartResponse.data) {
                servicePackageDiscountPart.push(servicePackageDiscountPartResponse.data);
            }
        }
        const availableLineItems = [
            resultMap.rainDefense,
            ...resultMap.supportingItems,
            ...resultMap.wipers,
            ...nullSafeGlassParts,
            ...servicePackageDiscountPart,
        ];

        // When calling pricing from the quote page, always use the cash parent account but save the existing one in case it's unverified insurance navigating backwards
        var holdParentAccountNumber = store.getters.order.payment?.parentAccountNumber;
        var holdBillToAccountNumber = store.getters.order.payment?.billToAccountNumber;

        baseMixin.methods.dispatchStoreAction(
            storeActions.SAVE_PARENT_ACCOUNT_NUMBER,
            applicationConfig.CASH_PARENT_ACCOUNT_NUMBER,
            false
        );
        baseMixin.methods.dispatchStoreAction(
            storeActions.SAVE_BILL_TO_ACCOUNT_NUMBER,
            applicationConfig.CASH_DEFAULT_BILL_TO_ACCOUNT_NUMBER,
            false
        );

        const pricingResults = await baseMixin.methods.dispatchStoreActionWithLogging(
            storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
            {
                availableLineItems: availableLineItems,
            },
            "quote",
            false
        );

        // This will remove any servicePackageDiscount item from lineItems.supportingItems
        baseMixin.methods.dispatchStoreAction(
            storeActions.SAVE_SUPPORTING_ITEMS,
            resultMap.supportingItems,
            false
        );
        lineItems.supportingItems = resultMap.supportingItems;
        const addableVaps = [...resultMap.wipers, resultMap.rainDefense];

        // Promo logic
        // Populate the previous state of promos for toast message usage in "next()"
        const oldActivePromos = store.getters.lineItems.promos?.slice(0);
        const oldInactivePromos = store.getters.order.payment.inactivePromos?.slice(0);

        const promoCodeFromQueryString = consumeQueryFromStash(queryStrings.PROMO);
        const { validatePromoResponse, revalidatePromoResponse } =
            await revalidatePromosAndValidateQueryStringPromo(
                promoCodeFromQueryString,
                pricingResults,
                "quote",
                true
            );
        // Sync local promos with any new promos added by validate/revalidate
        lineItems.promos = store.getters.lineItems.promos ?? [];
        // End of promo logic

        // Call the "next" function to complete the transition to this page.
        next(async (vm) => {
            vm.setCmsContent(resultMap.cmsContent);
            vm.showSaveProgressPopup = showSaveProgressPopup;
            vm.showSaveProgressModal = showSaveProgressModal;
            vm.addableVaps = addableVaps;
            vm.lineItems = lineItems;
            vm.availableLineItems = pricingResults;
            vm.holdParentAccountNumber = holdParentAccountNumber;
            vm.holdBillToAccountNumber = holdBillToAccountNumber;
            vm.skipToInsurance = shouldSkipToInsurance;

            if (revalidatePromoResponse) {
                const revalidateAlerts = buildToastMessagesFromRevalidateOrValidatePromoResponse(
                    revalidatePromoResponse,
                    oldActivePromos,
                    oldInactivePromos
                );
                revalidateAlerts.forEach((alert) => {
                    vm.$refs.funnelHeader.pushGlobalAlert(alert, alert.shouldAutoFade);
                });
            }
            if (validatePromoResponse) {
                const validateAlerts =
                    buildToastMessagesFromRevalidateOrValidatePromoResponse(validatePromoResponse);
                vm.$refs.funnelHeader.pushGlobalAlert(
                    validateAlerts[0],
                    validateAlerts[0].shouldAutoFade
                );
            }

            // This is a safeguard to prevent verified insurance from seeing quote page again.
            const payment = store.getters.payment;
            if (payment?.isInsurance && payment?.insuranceCoverage?.isVerified) {
                navigateToHeritageFunnel({ shouldSaveSession: true, pageNameToLog: "quote" });
            }

            const getIsInsuranceSelectedValue = (availableLineItems, insuranceThreshold) => {
                // Override auto-select if specified
                const quoteTypeParam = to.query?.offer?.toLowerCase();

                if (quoteTypeParam === ACCEPTED_QUOTE_TYPES.CASH) {
                    return false;
                } else if (quoteTypeParam === ACCEPTED_QUOTE_TYPES.INSURANCE) {
                    return true;
                }

                const serviceLocationState = store.getters.order.serviceLocation.state;

                // usually true when returning from heritage but can be false when returning from heritage on a save quote
                const isInsuranceFromQueryString = to.query?.isInsurance || to.query?.isinsurance;
                const defaultIsInsuranceSelectedValue = store.getters.order.payment.isInsurance;
                const hideRecalCost =
                    experimentMixin.methods
                        .getSettingValue(experimentSettings.RECAL_PRICE_REMOVE)
                        ?.toLowerCase() === "true";

                //Default to Insurance Tab if user Service zip is from certain States
                if (
                    serviceLocationState != null &&
                    payWithInsuranceStates.find((item) => item === serviceLocationState)
                ) {
                    return true;
                }

                if (defaultIsInsuranceSelectedValue != null) {
                    return defaultIsInsuranceSelectedValue;
                }

                if (availableLineItems) {
                    const lineItemsForCalculatingPrice = hideRecalCost
                        ? baseMixin.methods.filterOutFees(
                              baseMixin.methods.filterOutRecalibration(availableLineItems) // Strip out recal before filtering out fees
                          )
                        : baseMixin.methods.filterOutFees(availableLineItems);

                    const lineItemsNoDiscount =
                        baseMixin.methods.filterOutServicePackageDiscountPart(
                            lineItemsForCalculatingPrice
                        );

                    if (isInsuranceFromQueryString != null) {
                        if (isInsuranceFromQueryString.toLowerCase() === "true") {
                            return true;
                        }
                    }

                    const tierOnePrice =
                        baseMixin.methods.getTierOnePackagePrice(lineItemsNoDiscount);
                    // prettier-ignore
                    {
                        debugLog("quote tierOnePrice comparison: " + tierOnePrice + " > " + insuranceThreshold + "=" + (tierOnePrice > insuranceThreshold));
                    }

                    // compare base price vs arbitrary threshold (representing insurance price)
                    return tierOnePrice > insuranceThreshold;
                }

                return null;
            };

            let thresholdToUse = INSURANCE_TAB_TO_DISPLAY_THRESHOLD_DEFAULT;
            let internalThreshold = experimentMixin.methods.getSettingValue(
                experimentSettings.INSURANCE_TAB_TO_DISPLAY_THRESHOLD_INTERNAL
            );
            let externalThreshold = experimentMixin.methods.getSettingValue(
                experimentSettings.INSURANCE_TAB_TO_DISPLAY_THRESHOLD_EXTERNAL
            );
            const isExternalParameter = store.getters.externalParameterState?.isExternalParameter;

            // prettier-ignore
            {
                debugLog("--- quote.vue thresholds start ---");
                debugLog(" isExternalParameter: ", isExternalParameter);
                debugLog(" internalThreshold: ", internalThreshold);
                debugLog(" externalThreshold: ", externalThreshold);
                debugLog("--- quote.vue thresholds end ---");
            }

            if (isExternalParameter === externalParameterStatus.NOT_SET) {
                // prettier-ignore
                {
                    debugLog("quote.vue tab select EXTERNAL not set");
                }
                // there are no active or inactive external parameters; use internal threshold
                if (internalThreshold) thresholdToUse = internalThreshold;

                vm.isInsuranceSelected = getIsInsuranceSelectedValue(
                    vm.availableLineItems,
                    thresholdToUse
                );
                baseMixin.methods.ResetExternalParamsAndHideModal();
            } else {
                // user came from an external source, however, the externalParms may have been reset on service-zip, property-questions, etc...
                if (getBoolFromString(store.getters.externalParameterQuote?.isInsurance)) {
                    // prettier-ignore
                    {
                        debugLog("quote.vue tab select EXTERNAL ISINSURANCE");
                    }

                    const insuranceSelection = true;
                    const servicePackage = store.getters.externalParameterQuote.servicePackage;

                    if (
                        servicePackage != null &&
                        isExternalParameter === externalParameterStatus.ACTIVE
                    ) {
                        await vm.skip(insuranceSelection, servicePackage);
                    }

                    baseMixin.methods.ResetExternalParamsAndHideModal();
                } else {
                    if (externalThreshold) thresholdToUse = externalThreshold;

                    // prettier-ignore
                    {
                        debugLog("quote.vue tab select NOT EXTERNAL");
                    }

                    vm.isInsuranceSelected = getIsInsuranceSelectedValue(
                        vm.availableLineItems,
                        thresholdToUse
                    );
                    baseMixin.methods.ResetExternalParamsAndHideModal();
                }
            }

            if (vm.skipToInsurance && !vm.showSaveProgressPopup) {
                // skip ahead only if no email popup.
                await vm.skip(true, externalParamPackageLabels.GLASS_ONLY);
            }
        });
    },
    data() {
        return {
            isInsuranceSelected: null,
            availableLineItems: null,
            lineItems: [],
            addableVaps: [],
            servicePackage: null,
            holdParentAccountNumber: null,
            holdBillToAccountNumber: null,
            showSaveProgressPopup: null,
            showSaveProgressModal: null,
            isSaveProgressComplete: null,
            packageNumber: null,
            skipToInsurance: null,
        };
    },
    mounted() {
        this.attachCustomEventsForAnalytics();
    },
    computed: {
        lineItemsCloneForWatcher() {
            return Object.assign({}, this.lineItems);
        },
        isRecalibrationOnOrder() {
            return store.getters.isRecalibrationOnOrder;
        },
        isServicePackageDiscountOnOrder() {
            return containsLineItemWithPartType(
                partTypeStrings.SERVICE_PACKAGE_DISCOUNT,
                this.availableLineItems
            );
        },
        servicePackageDiscountParts() {
            return findLineItemsWithPartType(
                partTypeStrings.SERVICE_PACKAGE_DISCOUNT,
                this.availableLineItems
            );
        },
        shouldHideRecalibration() {
            return (
                experimentMixin.methods
                    .getSettingValue(experimentSettings.RECAL_PRICE_REMOVE)
                    ?.toLowerCase() === "true" && this.isRecalibrationOnOrder
            );
        },
        showAfterpayBanner() {
            return (
                !this.isInsuranceSelected &&
                (!this.isRecalibrationOnOrder || !this.shouldHideRecalibration)
            );
        },
        isRecalPriceRemove() {
            return (
                experimentMixin.methods
                    .getSettingValue(experimentSettings.RECAL_PRICE_REMOVE)
                    ?.toLowerCase() === "true"
            );
        },
        showRecalDisclaimer() {
            return this.isRecalibrationOnOrder && this.isRecalPriceRemove;
        },
        isAfterpayBreakoutDisplay() {
            return (
                (!this.isRecalPriceRemove || !this.isRecalibrationOnOrder) &&
                experimentMixin.methods.hasSettingEqualTo(
                    experimentSettings.DISPLAY_AFTERPAY_BREAKOUT_DISPLAY,
                    "true"
                )
            );
        },
    },
    methods: {
        getColCount() {
            if (this.packageNumber > 2) {
                return "col-xl-10";
            } else {
                return "col-xl-6";
            }
        },
        currentNumberOfPackagesAction(packageNumber) {
            this.packageNumber = packageNumber;
        },
        openModalAction(modalName) {
            this.$refs[modalName].openModal();
        },
        arePagePrerequisitesValid() {
            const payment = store.getters.order.payment;

            const preReqResult =
                store.getters.order.serviceLocation.zipCode &&
                store.getters.order.serviceLocation.zipCodeCtu &&
                (store.getters.order.damage.isRepair ||
                    (store.getters.order.lineItems?.glassParts != null &&
                        store.getters.order.lineItems.glassParts.length > 0)) &&
                (payment.insuranceCoverage?.isVerified == null ||
                    payment.insuranceCoverage?.isVerified === false);

            // prettier-ignore
            {
                debugLog("--- quote.vue pagePrereqs start ---", null, !preReqResult);
                debugLog("store.getters.order.serviceLocation.zipCode:", store.getters.order.serviceLocation?.zipCode, !preReqResult);
                debugLog("store.getters.order.serviceLocation.zipCodeCtu:", store.getters.order.serviceLocation?.zipCodeCtu, !preReqResult);
                debugLog("store.getters.order.damage.isRepair:", store.getters.order.damage?.isRepair, !preReqResult);
                debugLog("store.getters.order.lineItems?.glassParts:", store.getters.order.lineItems?.glassParts, !preReqResult);
                debugLog("store.getters.order.payemt.insuranceCoverage?.isVerified:", store.getters.order.payment?.insuranceCoverage?.isVerified, !preReqResult);
                debugLog("--- quote.vue pagePrereqs end ---", null, !preReqResult);
            }

            return preReqResult;
        },
        vapsItemsSelectedAction(vapsItemsSelected) {
            this.lineItems.vaps = vapsItemsSelected;
        },
        servicePackageDiscountSelectedAction(supportingItemsSelected) {
            this.lineItems.supportingItems = supportingItemsSelected;
        },
        backButtonAction() {
            vehicleQuestionsMixin.methods.navigateBack(this);
        },
        updateSaveProgressAsSaved() {
            this.showSaveProgressModal = false;
        },
        async closeSaveProgressPopup() {
            this.showSaveProgressPopup = false;

            await this.dispatchStoreAction(
                storeActions.SAVE_PAGE_DATA,
                {
                    page: routeData.QUOTE.name,
                    data: { saveProgressPopupSkipped: true },
                },
                false
            );

            if (this.skipToInsurance) {
                // skip ahead now if in IGQ skip experiment
                await this.skip(true, externalParamPackageLabels.GLASS_ONLY);
            }
        },
        forwardButtonAction() {
            this.dispatchStoreAction(
                this.storeActions.SAVE_PAYMENT_TYPE,
                this.isInsuranceSelected,
                false
            );

            if (!this.isInsuranceSelected) {
                this.dispatchStoreAction(
                    this.storeActions.SAVE_PARENT_ACCOUNT_NUMBER,
                    applicationConfig.CASH_PARENT_ACCOUNT_NUMBER,
                    false
                );
                this.dispatchStoreAction(
                    this.storeActions.SAVE_BILL_TO_ACCOUNT_NUMBER,
                    applicationConfig.CASH_DEFAULT_BILL_TO_ACCOUNT_NUMBER,
                    false
                );
            } else {
                baseMixin.methods.dispatchStoreAction(
                    storeActions.SAVE_PARENT_ACCOUNT_NUMBER,
                    this.holdParentAccountNumber,
                    false
                );
                baseMixin.methods.dispatchStoreAction(
                    storeActions.SAVE_BILL_TO_ACCOUNT_NUMBER,
                    this.holdBillToAccountNumber,
                    false
                );
            }

            if (
                this.$store.getters.order.payment.parentAccountNumber !=
                applicationConfig.CASH_PARENT_ACCOUNT_NUMBER
            ) {
                this.lineItems.supportingItems = this.filterOutFees(this.lineItems.supportingItems);
            }

            if (this.lineItems.glassParts?.length > 0) {
                this.dispatchStoreAction(
                    this.storeActions.SAVE_GLASS_PARTS_SUPPRESSING_STATE_RESETTING,
                    this.lineItems.glassParts,
                    false
                );
            }
            if (this.isInsuranceSelected && this.isServicePackageDiscountOnOrder) {
                let supportingItems = this.lineItems.supportingItems;
                supportingItems = supportingItems.filter((item) => {
                    return item.partType != this.servicePackageDiscountParts[0].partType;
                });
                this.dispatchStoreAction(
                    this.storeActions.SAVE_SUPPORTING_ITEMS,
                    supportingItems,
                    false
                );
            } else {
                this.dispatchStoreAction(
                    this.storeActions.SAVE_SUPPORTING_ITEMS,
                    this.lineItems.supportingItems,
                    false
                );
            }
            this.dispatchStoreAction(this.storeActions.SAVE_VAPS, this.lineItems.vaps, false);
            this.dispatchStoreAction(
                storeActions.SAVE_ACTIVE_AND_OR_INACTIVE_PROMOS,
                {
                    activePromos: this.lineItems.promos,
                },
                false
            );

            const payment = this.$store.getters.payment;
            if (payment.isInsurance) {
                this.$router.navigateWithSaving(
                    this.navigationScenarios.CLICKED_FORWARD_WITH_INSURANCE,
                    this.pageName
                );
            } else {
                this.$router.navigateWithSaving(
                    this.navigationScenarios.CLICKED_FORWARD_WITH_CASH,
                    this.pageName
                );
            }

            const lineItems = store.getters.order?.lineItems ?? {};
            const combinedLineItems = [
                ...(lineItems.glassParts || []),
                ...(lineItems.supportingItems || []),
                ...(lineItems.vaps || []),
                ...(lineItems.promos || []),
            ];

            const cashPriceSubtotal = combinedLineItems.length
                ? baseMixin.methods
                      .getTotalPriceOfAllLineItemsAndChildParts(combinedLineItems, false)
                      .toFixed(2)
                : "";

            store.commit(storeMutations.UPDATE_CASH_PRICE_SUBTOTAL, cashPriceSubtotal);
        },
        attachCustomEventsForAnalytics() {
            this.prependActionToMethod(this, this.forwardButtonAction, () => {
                if (!this.isInsuranceSelected && this.lineItems.vaps?.length == 0) {
                    const tierOnePrice =
                        this.lineItems.promos?.length > 0
                            ? this.$refs.servicePackage.getDiscountedPackagePriceString(
                                  packageNames.TIER_ONE,
                                  false
                              )
                            : this.$refs.servicePackage.getPackagePriceString(
                                  packageNames.TIER_ONE
                              );
                    this.pushEventToGA(
                        this.$route.query[this.queryStrings.FMG_PAGE],
                        this.GaActions.CASH_QUOTE_DISPLAYED,
                        tierOnePrice,
                        true
                    );
                }
            });
            this.$nextTick(() => {
                const availablePackageNames = this.$refs.servicePackage?.servicePackageAnswers;
                var priceLabel = "";

                if (availablePackageNames?.length > 1 || availablePackageNames?.length == 1) {
                    var tier = availablePackageNames[0];
                    if (tier) {
                        let lineItemsToPrice = this.availableLineItems;
                        if (this.isRecalibrationOnOrder && this.shouldHideRecalibration) {
                            lineItemsToPrice =
                                baseMixin.methods.filterOutRecalibration(lineItemsToPrice);
                        }
                        if (this.isServicePackageDiscountOnOrder) {
                            lineItemsToPrice = lineItemsToPrice?.filter((item) => {
                                return (
                                    item.partType != this.servicePackageDiscountParts[0].partType
                                );
                            });
                        }
                        let price = 0;
                        if (
                            tier.additionalButtonData?.servicePackageDiscount &&
                            this.isServicePackageDiscountOnOrder
                        ) {
                            lineItemsToPrice.push(...this.servicePackageDiscountParts);
                        }
                        price += baseMixin.methods.getTierOnePackagePrice(
                            baseMixin.methods.filterOutFees(lineItemsToPrice)
                        );
                        price += this.$refs.servicePackage.getVapsPrice(tier.value);
                        priceLabel = price.toFixed(2);
                    }
                }
                const subTotalLabel = this.Variables?.CASH_SUBTOTAL;
                this.pushVariableToDataLayer?.({ [subTotalLabel]: priceLabel });
            });
        },
        async skip(insuranceSelection, packageSelection) {
            this.isInsuranceSelected = insuranceSelection;
            this.servicePackage = packageSelection;

            // Allow selections to filter through sub-logic
            await nextTick();
            await nextTick();

            const isValid = await baseMixin.methods.isFormValid(this.$refs.theForm);
            if (isValid) {
                showFmgLoadingModal(true);
                await this.forwardButtonAction();
            }
        },
    },
    watch: {
        lineItemsCloneForWatcher: {
            handler(newValue, oldValue) {
                if (
                    !oldValue ||
                    oldValue.length == 0 ||
                    !oldValue.vaps ||
                    !newValue ||
                    newValue.length == 0
                ) {
                    return;
                }
                if (oldValue.promos.length < newValue.promos.length) {
                    const oldPromoCodes = oldValue.promos.map(
                        (promoObject) => promoObject.promoCode
                    );
                    const newlyActivatedPromoCodes = newValue.promos.filter(
                        (newPromo) => !oldPromoCodes.includes(newPromo.promoCode)
                    );
                    const alert = createPromoSuccessAlert(newlyActivatedPromoCodes[0].promoCode);
                    this.$refs.funnelHeader.pushGlobalAlert(alert, alert.shouldAutoFade);
                }
            },
            deep: true,
        },
    },
    components: {
        funnelHeader,
        navbar,
        funnelSubHeader,
        Form,
        textBlock,
        cashOrInsuranceQuestion,
        servicePackageQuestion,
        contentGroupModal,
        loadingModal,
        afterpayModalBanner,
        promoModalQuestion,
        recalDisclaimer,
        saveProgressModalQuestion,
        saveProgressPopupQuestion,
    },
};
</script>

<style lang="scss" scoped>
.quote-page.show-save-progress-popup .row.justify-content-center {
    display: none;

    &.funnel-header-wrapper,
    &.save-progress-popup {
        display: flex;
    }
}

.funnel-sub-header {
    p {
        font-size: 1rem;
    }
}
.text-block {
    display: block;
}
:deep(.promo-modal-question a) {
    @include responsive-font-size-md(0.875rem, 1rem);
}
</style>
