<template>
    <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
        <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-4 mt-5"
                        cmsWidgetName="LicensePlateNumberQuestionWidget"
                        v-model="licensePlate"
                        isRequired
                        customInputId="licensePlate"
                        validationRules="license-plate-required" />

                    <textboxQuestion
                        class="mb-4"
                        cmsWidgetName="RegistrationZipQuestionWidget"
                        v-model="registrationZipCode"
                        customInputId="zip"
                        mask="#####"
                        validationRules="registration-zip-required|zip-format" />

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

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

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

                    <alert
                        v-if="displayNonServiceableZipAlert"
                        class="my-3"
                        :manualHeadline="AlertNonServiceableZipHeader"
                        :manualCopy="AlertNonServiceableZipBody"
                        alertClass="alert-danger"
                        v-bind:isDismissible="false" />

                    <div class="row mt-2" v-if="showServiceZipField">
                        <div class="col mb-1">
                            <textboxQuestion
                                cmsWidgetName="ServiceZipQuestionWidget"
                                v-model="serviceZipCode"
                                inputId="serviceZipCode"
                                validationRules="zip-required|zip-format"
                                mask="#####" />
                        </div>
                    </div>

                    <alert
                        v-if="displayVinNotFoundAlert"
                        class="my-3"
                        cmsWidgetName="AlertVinNotFoundWidget"
                        alertClass="alert-danger"
                        v-bind:isDismissible="false" />

                    <alert
                        v-if="displayMatchedDifferentVehicleAlert"
                        class="my-3"
                        :manualHeadline="AlertMatchedDifferentVehicleHeader"
                        :manualCopy="AlertMatchedDifferentVehicleBody"
                        alertClass="alert-warning"
                        v-bind:isDismissible="false" />
                    <alert
                        ref="AlertNoService"
                        v-if="displayNoServiceAlert"
                        class="my-4"
                        cmsWidgetName="AlertNoServiceWidget"
                        alertClass="alert-danger"
                        v-bind:isDismissible="false" />

                    <navbar
                        ref="navbar"
                        cmsWidgetName="FunnelFooterWidget"
                        :isForwardActionDisabled="!meta.valid"
                        @back-clicked="backButtonAction"
                        @ForwardClicked="forwardButtonAction || displayNoServiceAlert" />
                </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 textBlock from "@/digital-components/text-block/text-block";

// 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, isGlassAvailableForCarId } from "@/helpers/damage-helper";
import { routerParams } from "@/router/router-constants/router-params";
import { required, regex } from "@/helpers/validation-rules";
import { Form, defineRule } from "vee-validate";
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("license-plate-required", required(errorMessages.LICENSE_PLATE_REQUIRED));
defineRule("registration-zip-required", required(errorMessages.REGISTRATION_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
    )
);

export default {
    name: "license-plate-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();
            }
        });
    },
    props: {
        validationRules: String,
    },
    data() {
        return {
            licensePlate: this.getLicensePlateFromStore(),
            registrationZipCode: this.getRegistrationZipFromStore() ?? this.$route.query.zipcode,
            emailOrSms: this.getEmailOrSmsFromStore(),
            serviceZipCode: this.getServiceZipFromStore(),
            carId: this.getCarIdfromStore(),
            isHeavyTruck: this.getIsVehicleHeavyTruckServiceableFromStore(),
            displayNonServiceableZipAlert: false,
            displayVinNotFoundAlert: false,
            displayMatchedDifferentVehicleAlert: false,
            previouslyEnteredCarId: "",
            isSelectedGlassAvailableForVehicle: true,
            isCarIdDifferent: false,
            customAlertData: {},
            displayInvalidZipAlert: false,
            showServiceZipField: this.getServiceZipFromStore(),
            isZipServiceable: false,
        };
    },
    methods: {
        arePagePrerequisitesValid() {
            return store.getters.vehicle.carId !== null;
        },
        backButtonAction() {
            // route to move backwards
            this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
        },
        attachCustomEvents() {
            this.prependActionToMethod(this, this.forwardButtonAction, () => {
                this.pushEventToGA(
                    this.$route.query[this.queryStrings.FMG_PAGE],
                    this.GaActions.SUBMITTED,
                    this.GaLabels.LICENSE_PLATE_LOOKUP,
                    true
                );
            });
        },
        getLicensePlateFromStore() {
            return this.$store.getters.vehicle.registration.licensePlate;
        },
        getRegistrationZipFromStore() {
            return this.$store.getters.vehicle.registration.zipCode;
        },
        getEmailOrSmsFromStore() {
            return this.$store.getters.emailOrSms;
        },
        getServiceZipFromStore() {
            return this.$store.getters.order.serviceLocation.zipCode;
        },
        getCarIdfromStore() {
            return store.getters.vehicle.carId;
        },
        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 },
                "license-plate-lookup"
            );
        },
        async forwardButtonAction() {
            this.resetWarningsAndErrors();

            const registrationZipValidationResponse = this.dispatchStoreActionWithLogging(
                storeActions.VALIDATE_ZIP,
                { zip: this.registrationZipCode },
                "license-plate-lookup"
            );

            // Settle promises and get results
            const promiseResultMap = [
                {
                    resultKey: "registrationZipValidationResponse",
                    promise: registrationZipValidationResponse,
                },
                {
                    // If serviceZipCode is not set, then sets the response to the registrationZipValidationResponse. Calls VALIDATE_ZIP if the serviceZipCode is set.
                    resultKey: "serviceZipValidationResponse",
                    promise: this.serviceZipCode
                        ? this.dispatchStoreActionWithLogging(
                              storeActions.VALIDATE_ZIP,
                              {
                                  zip: this.serviceZipCode,
                              },
                              "license-plate-lookup"
                          )
                        : registrationZipValidationResponse,
                },
            ];

            const resultMap = await settleAllPromises(promiseResultMap);

            if (!resultMap.registrationZipValidationResponse.isValid) {
                this.displayInvalidZipAlert = true;
                return this.$refs.navbar.removeLoader();
            }

            // Lookup vin
            const vinLookup = await this.lookupVin(
                this.licensePlate,
                resultMap.registrationZipValidationResponse.state
            ).catch(() => {
                // No VIN found.
                this.displayVinNotFoundAlert = true;
                return this.$refs.navbar.removeLoader();
            });
            // If no VIN was found, stop processing after displaying alert
            if (!vinLookup) {
                return;
            }

            // If a Service Zip is entered and it is an invalid zip code (ex. 11111) then show an alert
            const isZipValid = resultMap.serviceZipValidationResponse.isValid;
            if (this.serviceZipCode && !isZipValid) {
                this.displayInvalidZipAlert = true;
                return this.$refs.navbar.removeLoader();
            }
            // Check if the CarId has changed.
            this.isCarIdDifferent =
                vinLookup.data.vehicle.carId !== this.$store.getters.vehicle.carId;

            // Handle changing car
            if (
                this.isCarIdDifferent &&
                vinLookup.data.vehicle.carId !== this.previouslyEnteredCarId
            ) {
                // Display Alert
                this.previouslyEnteredCarId = vinLookup.data.vehicle.carId;
                this.customAlertData.vehicleInfo = vinLookup.data.vehicle;
                this.displayMatchedDifferentVehicleAlert = true;

                this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(
                    vinLookup.data.vehicle.carId,
                    "license-plate-lookup"
                );

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

            // If the either the registration zip code or service zip code are not serviceable
            this.isZipServiceable = resultMap.serviceZipValidationResponse.isServiceable;
            if (!this.isZipServiceable) {
                this.displayNonServiceableZipAlert = true;
                this.showServiceZipField = true;
                return this.$refs.navbar.removeLoader();
            }

            // If the registration zip code is serviceable and nothing was entered for the service zip code
            // then set the service zip code to the registration zip code
            if (!this.serviceZipCode) {
                this.serviceZipCode = this.registrationZipCode;
            }

            // Save vin, vehicle, customer, service and registration information
            await this.dispatchStoreAction(
                storeActions.SAVE_REGISTRATION_LICENSE_PLATE_LOOKUP,
                {
                    isSelectedGlassAvailableForVehicle: this.isSelectedGlassAvailableForVehicle,
                    vehicleInfo: Object.assign(vinLookup.data.vehicle, { vin: vinLookup.data.vin }),
                    registrationInfo: {
                        licensePlate: this.licensePlate,
                    },
                },
                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
            );

            await this.dispatchStoreAction(
                storeActions.SAVE_SERVICE_ZIP_CODE_INFO,
                {
                    state: resultMap.serviceZipValidationResponse.state,
                    zipCode: this.serviceZipCode,
                    zipCodeCtu: resultMap.serviceZipValidationResponse.zipCodeCtu,
                },
                false
            );

            await this.getAndSaveBillToAccountNumber();
            return await this.navigateForward();
        },
        lookupVin(plate, state) {
            return this.dispatchStoreActionWithLogging(
                storeActions.LOOKUP_VIN_BY_PLATE,
                { licensePlate: plate, licenseState: state },
                "license-plate-lookup",
                false
            );
        },
        async navigateForward() {
            if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
                this.$router.navigateWithSaving(
                    this.navigationScenarios.CLICKED_FORWARD,
                    this.$route,
                    {},
                    { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true }
                );
            } else {
                await this.navigateForwardWithSingleCarMatch();
            }
        },
        resetWarningsAndErrors() {
            this.displayVinNotFoundAlert = false;
            this.displayNonServiceableZipAlert = false;
            this.displayMatchedDifferentVehicleAlert = false;
            this.displayVinLookupByHomeAddressNotAllowedAlert = false;
            this.displayInvalidZipAlert = false;
        },
    },
    mounted() {
        this.attachCustomEvents();
    },
    computed: {
        AlertNonServiceableZipHeader() {
            const zipCode = this.serviceZipCode ? this.serviceZipCode : this.registrationZipCode;
            return this.getCmsContent("AlertNonServiceableZipWidget", "HeadlineText").replaceAll(
                "{custom:serviceZip}",
                zipCode
            );
        },
        AlertNonServiceableZipBody() {
            return this.getCmsContent("AlertNonServiceableZipWidget", "BodyText");
        },
        AlertMatchedDifferentVehicleHeader() {
            return this.getCmsContent(
                "AlertMatchedDifferentVehicleWidget",
                "HeadlineText"
            ).replaceAll("{custom:damage}", getDamageString());
        },
        AlertMatchedDifferentVehicleBody() {
            return this.getCmsContent("AlertMatchedDifferentVehicleWidget", "BodyText")
                .replaceAll("{custom:damage}", getDamageString())
                .replaceAll("{custom:plateLookupYear}", this.customAlertData?.vehicleInfo?.year)
                .replaceAll("{custom:plateLookupMake}", this.customAlertData?.vehicleInfo?.make)
                .replaceAll("{custom:plateLookupModel}", this.customAlertData?.vehicleInfo?.model);
        },
    },
    watch: {
        licensePlate() {
            this.$refs.navbar.updateButtonText(
                this.getCmsContent("FunnelFooterWidget", "ForwardButtonText")
            );
        },
        registrationZipCode() {
            this.$refs.navbar.updateButtonText(
                this.getCmsContent("FunnelFooterWidget", "ForwardButtonText")
            );
        },
        serviceZipCode() {
            // If they modify the service zip code, then hide the error message.
            this.displayNonServiceableZipAlert = false;
            this.$refs.navbar.updateButtonText(
                this.getCmsContent("FunnelFooterWidget", "ForwardButtonText")
            );
        },
    },
    components: {
        funnelHeader,
        navbar,
        funnelSubHeader,
        textboxQuestion,
        alert,
        textBlock,
        Form,
    },
};
</script>
