<template>
    <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
        <loadingModal ref="loadingModal" />
        <div class="container-fluid page-container-grouped-styles">
            <div class="row justify-content-center">
                <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 cmsWidgetName="FunnelSubHeaderWidget" />
                    <textboxQuestion
                        class="mb-2 mt-5"
                        cmsWidgetName="VinNumberQuestionWidget"
                        v-model="vin"
                        customInputId="vin"
                        isRequired
                        :validationRules="!vinPopulatedOnPageLoad ? 'vin-required|vin-format' : ''"
                        :isDisabled="vinPopulatedOnPageLoad"
                        maxLength="17"
                        :mask="vinMask"
                        includeImageQuestion
                        :imageQuestionSubmitHandler="getVinFromImage"
                        :maxFileSize="imageUploadMaxFileSize"
                        @image-lookup-error="displayVinScanAlert"
                        @image-validity-error="displayVinScanAlert"
                        data-test="vin-lookup-field"
                        ref="vinLookupQuestion" />

                    <alert
                        cmsWidgetName="AlertVinScanFailed"
                        v-if="displayVinScanFailedAlert"
                        alertClass="alert-danger" />

                    <vinInformation class="mb-4" />

                    <textboxQuestion
                        class="mb-4"
                        cmsWidgetName="ServiceZipQuestionWidget"
                        v-model="serviceZipCode"
                        customInputId="serviceZipCode"
                        mask="#####"
                        isRequired
                        validationRules="zip-required|zip-format" />

                    <textboxQuestion
                        cmsWidgetName="EmailAddressQuestionWidget"
                        v-model="emailOrSms"
                        customInputId="emailOrSms"
                        :isRequired="!IsEmailOptional"
                        :validationRules="EmailOrSmsValidationRules"
                        :addOptionalText="IsEmailOptional" />

                    <textBlock cmsWidgetName="QuoteEmailTextBlockWidget" typeStyle="caption" />

                    <alert
                        ref="alertInvalidZip"
                        v-if="displayInvalidZipAlert"
                        class="my-4"
                        cmsWidgetName="AlertInvalidZipWidget"
                        alertClass="alert-danger"
                        v-bind:isDismissible="false" />

                    <alert
                        class="my-4"
                        :manualHeadline="AlertPerfectMatchInsuranceVerifiedHeader"
                        :manualCopy="AlertPerfectMatchInsuranceVerifiedBody"
                        v-model="customAlertData"
                        v-if="
                            vinPopulatedOnPageLoad &&
                            isInsuranceVerified &&
                            !displayInvalidZipAlert &&
                            !displayNonServiceableZipAlert
                        "
                        alertClass="alert-success" />

                    <alert
                        class="my-4"
                        :manualHeadline="AlertMatchedDifferentVehicleHeader"
                        :manualCopy="AlertMatchedDifferentVehicleBody"
                        v-model="customAlertData"
                        v-if="displayMatchedDifferentVehicleAlert"
                        alertClass="alert-warning" />

                    <alert
                        class="my-4"
                        :manualHeadline="AlertNonServiceableZipHeader"
                        :manualCopy="AlertNonServiceableZipBody"
                        v-model="customAlertData"
                        v-if="displayNonServiceableZipAlert"
                        alertClass="alert-danger" />

                    <alert
                        class="my-4"
                        v-model="customAlertData"
                        v-if="displayVinNotFoundAlert"
                        alertClass="alert-danger"
                        cmsWidgetName="AlertVinNotFoundWidget" />

                    <alert
                        class="my-4"
                        :manualHeadline="AlertPerfectMatchInsuranceNotVerifiedHeader"
                        :manualCopy="AlertPerfectMatchInsuranceNotVerifiedBody"
                        v-model="customAlertData"
                        v-if="
                            vinPopulatedOnPageLoad &&
                            !isInsuranceVerified &&
                            !displayInvalidZipAlert &&
                            !displayNonServiceableZipAlert
                        "
                        alertClass="alert-success" />

                    <navbar
                        cmsWidgetName="FunnelFooterWidget"
                        ref="navbar"
                        :isForwardActionDisabled="!meta.valid"
                        @back-clicked="backButtonAction"
                        @ForwardClicked="forwardButtonAction" />
                </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 alert from "@/ux-components/alert/alert";
import textboxQuestion from "@/digital-components/textbox-question/textbox-question";
import vinInformation from "@/layouts/vin-lookup/vin-information/vin-information";
import textBlock from "@/digital-components/text-block/text-block";
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";

// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
import { storeActions } from "@/constants/store-actions";
import { errorMessages } from "@/constants/error-messages";
import {
    getDamageString,
    getIsWindshieldOnly,
    isGlassAvailableForCarId,
} from "@/helpers/damage-helper";
import { required, regex } from "@/helpers/validation-rules";
import { Form, defineRule } from "vee-validate";
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
import { routerParams } from "@/router/router-constants/router-params";
import baseMixin from "@/mixins/base-mixin.js";
import store from "@/store";
import vinPagesMixin from "@/mixins/vin-pages-mixin";
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";

// DEFINE VALIDATION RULES
defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
defineRule("zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT));
defineRule("email-sms-required", required(errorMessages.EMAIL_SMS_REQUIRED));
defineRule(
    "email-sms-format",
    regex(
        /^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9-]+)\.([a-zA-Z]{2,})$|^\(?(\d{3})\)?[-. ]?(\d{3})[-. ]?(\d{4})$/,
        errorMessages.EMAIL_SMS_FORMAT
    )
);
defineRule("vin-required", required(errorMessages.VIN_REQUIRED));
defineRule("vin-format", regex(/^[a-hA-Hj-nJ-NpPr-zR-Z0-9]{17}$/, errorMessages.VIN_FORMAT));

export default {
    name: "vin-lookup",
    mixins: [vinPagesMixin],
    async beforeRouteEnter(to, from, next) {
        // Call APIs
        const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);

        // Settle promises and get results
        const promiseResultMap = [
            {
                resultKey: "cmsContent",
                promise: cmsContentPromise,
            },
        ];

        const resultMap = await settleAllPromises(promiseResultMap);

        // Call the "next" function to complete the transition to this page.
        next((vm) => {
            vm.setCmsContent(resultMap.cmsContent);
            if (store.getters.externalParameterState?.isExternalParameter) {
                baseMixin.methods.ResetExternalParamsAndHideModal();
            }
        });
    },
    data() {
        return {
            vin: this.getVinFromStore(),
            serviceZipCode: this.getZipFromStore() ?? this.$route.query.zipcode,
            emailOrSms: this.getEmailOrSmsFromStore(),
            carId: this.getCarIdfromStore(),
            isHeavyTruck: this.getIsVehicleHeavyTruckServiceableFromStore(),
            isCarIdDifferent: false,
            customAlertData: {},
            previouslyEnteredCarId: "",
            vinPopulatedOnPageLoad: this.getVinFromStore()?.length > 0,
            isSelectedGlassAvailableForVehicle: true,
            displayInvalidZipAlert: false,
            displayNonServiceableZipAlert: false,
            displayVinNotFoundAlert: false,
            displayMatchedDifferentVehicleAlert: false,
            displayVinScanFailedAlert: false,
        };
    },
    methods: {
        arePagePrerequisitesValid() {
            return store.getters.vehicle.carId !== null;
        },
        getEmailOrSmsFromStore() {
            return this.$store.getters.emailOrSms;
        },
        getVinFromStore() {
            return this.$store.getters.vehicle.vin;
        },
        getZipFromStore() {
            return this.$store.getters.order.serviceLocation.zipCode;
        },
        attachCustomEvents() {
            this.prependActionToMethod(this, this.forwardButtonAction, () => {
                this.pushEventToGA(
                    this.$route.query[this.queryStrings.FMG_PAGE],
                    this.GaActions.SUBMITTED,
                    this.GaLabels.VIN_LOOKUP,
                    true
                );
            });
        },
        backButtonAction() {
            if (this.$store.getters.vehicle.vin) {
                this.$router.navigateWithoutSaving(
                    this.navigationScenarios.CLICKED_BACK_WITH_VIN,
                    this.$route
                );
            } else {
                this.$router.navigateWithoutSaving(
                    this.navigationScenarios.CLICKED_BACK,
                    this.$route
                );
            }
        },
        getIsVehicleHeavyTruckServiceableFromStore() {
            return store.getters.vehicle.isBigTruck && store.getters.vehicle.canSafeliteService;
        },
        async findClosestApplicableShops() {
            return await this.dispatchStoreActionWithLogging(
                storeActions.GET_CLOSEST_APPLICABLE_SHOPS,
                { zip: this.serviceZipCode, carId: this.carId },
                "vin-lookup"
            );
        },
        async forwardButtonAction() {
            this.resetAlerts();

            // If this is a new VIN Lookup, do both a Vehicle Lookup and a Zip Validation
            if (!this.vinPopulatedOnPageLoad) {
                const vehicleLookupResponse = this.dispatchStoreActionWithLogging(
                    storeActions.LOOKUP_VEHICLE_BY_VIN,
                    { vin: this.vin },
                    "vin-lookup"
                );

                // Settle promises and get results
                const promiseResultMap = [
                    {
                        resultKey: "vehicleLookupResponse",
                        promise: vehicleLookupResponse,
                    },
                    {
                        resultKey: "zipCodeData",
                        promise: this.getZipCodeData(this.serviceZipCode),
                    },
                ];

                const resultMap = await settleAllPromises(promiseResultMap);

                // If a Service Zip is entered and it is an invalid zip code (ex. 11111) then show an alert
                const isZipValid = resultMap.zipCodeData.isValid;
                if (this.serviceZipCode && !isZipValid) {
                    this.displayInvalidZipAlert = true;
                    return this.$refs.navbar.removeLoader();
                }
                this.displayInvalidZipAlert = false;
                // If either lookup fails, remove the loader and stop processing the page.
                if (!resultMap.vehicleLookupResponse || !resultMap.zipCodeData.isServiceable) {
                    // If the vehicle result is undefined, the vin entered was invalid.
                    if (!resultMap.vehicleLookupResponse) {
                        this.displayVinNotFoundAlert = true;
                    }

                    // Check if Service Zip entered is serviceable, if not display an alert
                    if (!resultMap.zipCodeData.isServiceable) {
                        this.displayNonServiceableZipAlert = true;
                    }

                    // Remove loader and stop processing the page.
                    return this.$refs.navbar.removeLoader();
                }

                // Check if the CarId is different from the lookup vs what is in state currently.
                this.isCarIdDifferent =
                    resultMap.vehicleLookupResponse.carId !== this.$store.getters.vehicle.carId;

                if (
                    this.isCarIdDifferent &&
                    resultMap.vehicleLookupResponse.carId !== this.previouslyEnteredCarId
                ) {
                    this.previouslyEnteredCarId = resultMap.vehicleLookupResponse.carId;
                    this.customAlertData.vehicleInfo = resultMap.vehicleLookupResponse;
                    this.displayMatchedDifferentVehicleAlert = true;

                    this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(
                        resultMap.vehicleLookupResponse.carId,
                        "vin-lookup"
                    );

                    // Update button "Continue with..."
                    this.$refs.navbar.updateButtonText(
                        `Continue with ${resultMap.vehicleLookupResponse.year} ${resultMap.vehicleLookupResponse.make} ${resultMap.vehicleLookupResponse.model}`
                    );
                    return this.$refs.navbar.removeLoader();
                }

                // Save vin, vehicle, customer and service information
                await this.dispatchStoreAction(
                    storeActions.SAVE_VIN_LOOKUP,
                    {
                        isSelectedGlassAvailableForVehicle: this.isSelectedGlassAvailableForVehicle,
                        vehicleInfo: Object.assign(resultMap.vehicleLookupResponse, {
                            vin: this.vin,
                        }),
                    },
                    false
                );
                if (this.isHeavyTruck) {
                    const closestShops = await this.findClosestApplicableShops(
                        this.serviceZipCode,
                        this.carId
                    );
                    this.displayNoServiceAlert = !closestShops?.data?.providers?.length;
                    if (this.displayNoServiceAlert) {
                        return this.$refs.navbar.removeLoader();
                    }
                }

                // if no value due to field being optional, blank both phone and email address

                // if no value due to field being optional, blank both phone and email address
                if (!this.emailOrSms) {
                    await this.dispatchStoreAction(storeActions.SAVE_PHONE_NUMBER, "", false);
                    await this.dispatchStoreAction(storeActions.SAVE_EMAIL, "", false);
                } else {
                    if (vinPagesMixin.methods.isPhoneNumber(this.emailOrSms)) {
                        const phone = this.emailOrSms.replace(/[()]/g, "");
                        await this.dispatchStoreAction(
                            storeActions.SAVE_PHONE_NUMBER,
                            phone,
                            false
                        );
                    } else {
                        await this.dispatchStoreAction(
                            storeActions.SAVE_EMAIL,
                            this.emailOrSms,
                            false
                        );
                    }
                }

                await this.dispatchStoreAction(
                    storeActions.SAVE_PAGE_DATA,
                    {
                        page: fmgPageValues.EMAIL_SMS_PAGES,
                        data: { emailOrSmsValue: this.emailOrSms },
                    },
                    false
                );
                await this.dispatchStoreAction(
                    storeActions.SAVE_SERVICE_ZIP_CODE_INFO,
                    {
                        state: resultMap.zipCodeData.state,
                        zipCode: this.serviceZipCode,
                        zipCodeCtu: resultMap.zipCodeData.zipCodeCtu,
                    },
                    false
                );

                await this.getAndSaveBillToAccountNumber();
                return await this.navigateForward();
            }

            // If a VIN has already been found. Validate the Service Zip (in case of changes)
            const zipCodeData = await this.getZipCodeData(this.serviceZipCode);

            // Check if Service Zip entered is serviceable then save the ZIP info
            if (zipCodeData.isServiceable) {
                //Only save the zipCode, state, and zipCodeCtu if the zip changed or we lack zipCodeCtu
                if (
                    this.$store.getters.order.serviceLocation.zipCode != this.serviceZipCode ||
                    !this.$store.getters.order.serviceLocation.zipCodeCtu
                ) {
                    await this.dispatchStoreAction(
                        storeActions.SAVE_SERVICE_ZIP_CODE_INFO,
                        {
                            state: zipCodeData.state,
                            zipCode: this.serviceZipCode,
                            zipCodeCtu: zipCodeData.zipCodeCtu,
                        },
                        false
                    );
                }
                // if no value due to field being optional, blank both phone and email address
                if (!this.emailOrSms) {
                    await this.dispatchStoreAction(storeActions.SAVE_PHONE_NUMBER, "", false);
                    await this.dispatchStoreAction(storeActions.SAVE_EMAIL, "", false);
                } else {
                    if (vinPagesMixin.methods.isPhoneNumber(this.emailOrSms)) {
                        const phone = this.emailOrSms.replace(/[()]/g, "");
                        await this.dispatchStoreAction(
                            storeActions.SAVE_PHONE_NUMBER,
                            phone,
                            false
                        );
                    } else {
                        await this.dispatchStoreAction(
                            storeActions.SAVE_EMAIL,
                            this.emailOrSms,
                            false
                        );
                    }
                }

                await this.dispatchStoreAction(
                    storeActions.SAVE_PAGE_DATA,
                    {
                        page: fmgPageValues.EMAIL_SMS_PAGES,
                        data: { emailOrSmsValue: this.emailOrSms },
                    },
                    false
                );

                return await this.navigateForward();
            }

            // If the Service Zip is NOT serviceable then show an alert
            if (zipCodeData.isValid) {
                this.displayNonServiceableZipAlert = true;
            } else {
                this.displayInvalidZipAlert = true;
            }

            return this.$refs.navbar.removeLoader();
        },
        async navigateForward() {
            if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
                this.$router.navigateWithSaving(
                    this.navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS,
                    this.$route,
                    {},
                    { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true }
                );
            } else {
                await this.navigateForwardWithSingleCarMatch();
            }
        },
        displayVinScanAlert() {
            this.displayVinScanFailedAlert = true;
        },
        getVinFromImage(image) {
            return new Promise((resolve, reject) => {
                this.dispatchStoreActionWithLogging(
                    storeActions.LOOKUP_VIN_BY_IMAGE,
                    image,
                    "vin-lookup"
                )
                    .then((response) => {
                        if (response.data.length > 0) {
                            resolve(response.data[0]);
                        } else {
                            reject("No VINs detected.");
                        }
                    })
                    .catch(() => {
                        reject("An error occurred during the lookup.");
                    });
            });
        },
        resetAlerts() {
            this.displayMatchedDifferentVehicleAlert = false;
            this.displayNonServiceableZipAlert = false;
            this.displayInvalidZipAlert = false;
            this.displayVinNotFoundAlert = false;
            this.displayVinScanFailedAlert = false;
            this.displayNoServiceAlert = false;
            this.displayNoServiceAlert = false;
        },
    },
    mounted() {
        this.attachCustomEvents();
    },
    computed: {
        AlertMatchedDifferentVehicleHeader() {
            return this.getCmsContent(
                "AlertMatchedDifferentVehicleWidget",
                "HeadlineText"
            ).replaceAll("{custom:damage}", getDamageString());
        },
        AlertMatchedDifferentVehicleBody() {
            return this.getCmsContent("AlertMatchedDifferentVehicleWidget", "BodyText")
                .replaceAll("{custom:damage}", getDamageString())
                .replaceAll("{custom:vinlookupYear}", this.customAlertData?.vehicleInfo?.year)
                .replaceAll("{custom:vinlookupMake}", this.customAlertData?.vehicleInfo?.make)
                .replaceAll("{custom:vinlookupModel}", this.customAlertData?.vehicleInfo?.model);
        },
        AlertNonServiceableZipHeader() {
            return this.getCmsContent("AlertNonServiceableZipWidget", "HeadlineText").replaceAll(
                "{custom:serviceZip}",
                this.serviceZipCode
            );
        },
        AlertNonServiceableZipBody() {
            return this.getCmsContent("AlertNonServiceableZipWidget", "BodyText");
        },
        AlertPerfectMatchInsuranceNotVerifiedHeader() {
            return this.getCmsContent("AlertPerfectMatchInsuranceNotVerified", "HeadlineText");
        },
        AlertPerfectMatchInsuranceNotVerifiedBody() {
            return this.getCmsContent(
                "AlertPerfectMatchInsuranceNotVerified",
                "BodyText"
            ).replaceAll("{custom:damage}", getDamageString());
        },
        AlertPerfectMatchInsuranceVerifiedHeader() {
            return this.getCmsContent("AlertPerfectMatchInsuranceVerified", "HeadlineText");
        },
        AlertPerfectMatchInsuranceVerifiedBody() {
            return this.getCmsContent("AlertPerfectMatchInsuranceVerified", "BodyText").replaceAll(
                "{custom:damage}",
                getIsWindshieldOnly()
            );
        },
        isInsuranceVerified() {
            return (
                store.getters.payment.insuranceCoverage.isVerified ||
                getFunnelCookie().HasDelayedClaimRegistration
            );
        },
        vinMask() {
            if (this.vinPopulatedOnPageLoad) {
                const lastSixChars = this.vin.substring(11, this.vin.length);
                return `!X!X!X!X!X!X!X!X!X!X!X${lastSixChars}`;
            } else {
                return "XXXXXXXXXXXXXXXXX";
            }
        },
        imageUploadMaxFileSize() {
            let kiloBytes = 5140;

            return kiloBytes * 1028;
        },
    },
    watch: {
        vin() {
            this.displayVinNotFoundAlert = false;
            this.displayVinScanFailedAlert = false;
            this.$refs.navbar.updateButtonText(
                this.getCmsContent("FunnelFooterWidget", "ForwardButtonText")
            );
        },
        serviceZipCode() {
            this.displayNonServiceableZipAlert = false;
        },
    },
    components: {
        funnelHeader,
        navbar,
        funnelSubHeader,
        textboxQuestion,
        alert,
        vinInformation,
        textBlock,
        Form,
        loadingModal,
    },
};
</script>
