<template>
    <Form
        @submit="onSubmit"
        @invalid-submit="onInvalidSubmit"
        ref="theForm"
        v-slot="{ meta }"
        autocomplete="off">
        <div class="container-fluid page-container-grouped-styles" id="address-lookup">
            <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" ref="funnelSubHeader" />

                    <customerQuestions
                        ref="customerQuestions"
                        v-model="customerQuestions"
                        :validationRules="EmailOrSmsValidationRules"
                        :isEmailOptional="IsEmailOptional" />
                    <alert
                        ref="alertVinNotFound"
                        v-if="displayVinNotFoundAlert"
                        class="mb-4"
                        cmsWidgetName="AlertVinNotFoundWidget"
                        alertClass="alert-danger"
                        v-bind:isDismissible="false" />

                    <alert
                        ref="alertMatchedDifferentVehicle"
                        v-if="displayMatchedDifferentVehicleAlert"
                        class="mb-4"
                        :manualHeadline="AlertMatchedDifferentVehicleHeader"
                        :manualCopy="AlertMatchedDifferentVehicleBody"
                        alertClass="alert-warning"
                        v-bind:isDismissible="false" />

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

                    <alert
                        ref="alertNonServiceableZip"
                        v-if="displayNonServiceableZipAlert"
                        class="mb-4"
                        alertClass="alert-danger"
                        :manualHeadline="AlertNonServiceableZipHeader"
                        :manualCopy="AlertNonServiceableZipBody"
                        v-bind:isDismissible="false" />

                    <alert
                        ref="alertVinLookupsByHomeAddressNotAllowed"
                        v-if="displayVinLookupByHomeAddressNotAllowedAlert"
                        class="mb-4"
                        cmsWidgetName="AlertVinLookupsByHomeAddressNotAllowedWidget"
                        alertClass="alert-danger"
                        v-bind:isDismissible="false" />

                    <transition name="fade" mode="out-in">
                        <div
                            class="service-zip-field"
                            v-if="showServiceZipField"
                            aria-live="polite">
                            <div class="row mt-4 mb-1">
                                <div class="col">
                                    <textboxQuestion
                                        cmsWidgetName="ServiceZipQuestionWidget"
                                        v-model="serviceZipCode"
                                        ref="serviceZip"
                                        customInputId="serviceZip"
                                        aria-haspopup=""
                                        mask="#####"
                                        validationRules="service-zip-required|service-zip-format" />
                                </div>
                            </div>
                        </div>
                    </transition>
                    <navbar
                        cmsWidgetName="FunnelFooterWidget"
                        ref="navbar"
                        :isDisabled="!meta.valid"
                        @ForwardClicked="forwardButtonAction"
                        @back-clicked="backButtonAction"
                        :isForwardActionDisabled="!meta.valid" />
                </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 customerQuestions from "@/layouts/address-lookup/customer-questions/customer-questions";
import alert from "@/ux-components/alert/alert";
import textboxQuestion from "@/digital-components/textbox-question/textbox-question";

import { Form, defineRule } from "vee-validate";
import { required, regex } from "@/helpers/validation-rules";
import { errorMessages } from "@/constants/error-messages";

// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
import { storeActions } from "@/constants/store-actions";
import { routerParams } from "@/router/router-constants/router-params";
import { getDamageString, isGlassAvailableForCarId } from "@/helpers/damage-helper";
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 - Note: Additional rules are defined in Customer Questions and Address Questions components
defineRule("service-zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
defineRule(
    "service-zip-format",
    regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT)
);

export default {
    name: "address-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 {
            customerQuestions: {
                addressQuestions: {
                    streetAddress: this.getRegistrationAddressFromStore(),
                    city: this.getRegistrationCityFromStore(),
                    state: this.getRegistrationStateFromStore(),
                    zipCode: this.getRegistrationZipFromStore(),
                },
                firstName: this.getRegistrationFirstNameFromStore(),
                lastName: this.getRegistrationLastNameFromStore(),
                emailOrSms: this.getEmailOrSmsFromStore(),
            },
            serviceZipCode: this.getServiceZipFromStore(),
            carId: this.getCarIdfromStore(),
            isHeavyTruck: this.getIsVehicleHeavyTruckServiceableFromStore(),
            displayNonServiceableZipAlert: false,
            displayVinNotFoundAlert: false,
            displayMatchedDifferentVehicleAlert: false,
            displayVinLookupByHomeAddressNotAllowedAlert: false,
            previouslyEnteredCarId: "",
            isCarIdDifferent: false,
            isSelectedGlassAvailableForVehicle: true,
            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.ADDRESS_LOOKUP,
                    true
                );
            });
        },
        getRegistrationAddressFromStore() {
            return this.$store.getters.vehicle.registration.address;
        },
        getRegistrationCityFromStore() {
            return this.$store.getters.vehicle.registration.city;
        },
        getRegistrationStateFromStore() {
            return this.$store.getters.vehicle.registration.state;
        },
        getRegistrationZipFromStore() {
            return this.$store.getters.vehicle.registration.zipCode;
        },
        getRegistrationFirstNameFromStore() {
            return this.$store.getters.vehicle.registration.firstName;
        },
        getRegistrationLastNameFromStore() {
            return this.$store.getters.vehicle.registration.lastName;
        },
        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 },
                "address-lookup"
            );
        },
        async forwardButtonAction() {
            this.resetWarningsAndErrors();

            // Vehicle info change in the flow, use a variable to keep track and commit to state at the end.
            let vehicleInfoToCommit = {};

            const vinLookupResponse = this.dispatchStoreActionWithLogging(
                storeActions.LOOKUP_VIN_BY_ADDRESS,
                {
                    licenseLastName: this.customerQuestions.lastName,
                    licenseStreetAddress: this.customerQuestions.addressQuestions.streetAddress,
                    licenseZip: this.customerQuestions.addressQuestions.zipCode,
                    licenseState: this.customerQuestions.addressQuestions.state,
                },
                "address-lookup",
                false
            );

            // Settle promises and get results
            const promiseResultMap = [
                {
                    resultKey: "vinLookupResponse",
                    promise: vinLookupResponse,
                },
                {
                    resultKey: "serviceZipValidationResponse",
                    promise: this.serviceZipCode
                        ? this.dispatchStoreActionWithLogging(
                              storeActions.VALIDATE_ZIP,
                              {
                                  zip: this.serviceZipCode,
                              },
                              "address-lookup"
                          )
                        : this.dispatchStoreActionWithLogging(
                              storeActions.VALIDATE_ZIP,
                              {
                                  zip: this.customerQuestions.addressQuestions.zipCode,
                              },
                              "address-lookup"
                          ),
                },
            ];

            const resultMap = await settleAllPromises(promiseResultMap);
            // If VIN Lookup by address is forbidden by State Restrictions then show an alert
            if (!resultMap.vinLookupResponse.isStatePermissible) {
                // State Restrictions forbid lookup by address
                this.displayVinLookupByHomeAddressNotAllowedAlert = true;
                return this.$refs.navbar.removeLoader();
            }

            // 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();
            }
            this.displayInvalidZipAlert = false;
            const carsFound = resultMap.vinLookupResponse.vinVehicles;

            // Handle cases for different amounts of VINS found for the address.
            if (carsFound.length == 1) {
                // Single VIN found
                const carFound = carsFound[0].vehicle;

                this.isCarIdDifferent = carFound.carId !== this.$store.getters.vehicle.carId;
                if (this.isCarIdDifferent && carFound.carId !== this.previouslyEnteredCarId) {
                    // Display Alert
                    this.previouslyEnteredCarId = carFound.carId;
                    this.customAlertData.vehicleInfo = carFound;
                    this.displayMatchedDifferentVehicleAlert = true;

                    this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(
                        carFound.carId,
                        "address-lookup"
                    );

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

                // update data if the zip or service zip is serviceable
                vehicleInfoToCommit = Object.assign(carFound, { vin: carsFound[0].vin });
            } else if (carsFound.length > 1) {
                // If multiple cars were found and one and only one of them matches the carId entered, save the vehicle info
                // so we can go to the Heritage Funnel directly
                const matchingCars = carsFound.filter(
                    (vin) => vin.vehicle.carId === this.$store.getters.vehicle.carId
                );

                if (matchingCars.length === 1) {
                    vehicleInfoToCommit = Object.assign(matchingCars[0].vehicle, {
                        vin: matchingCars[0].vin,
                    });
                }
            } else {
                // No VINS found.
                this.displayVinNotFoundAlert = true;
                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.customerQuestions.addressQuestions.zipCode;
            }

            // Save vehicle, customer, service and registration information
            await this.dispatchStoreAction(
                storeActions.SAVE_REGISTRATION_ADDRESS_LOOKUP,
                {
                    isSelectedGlassAvailableForVehicle: this.isSelectedGlassAvailableForVehicle,
                    vehicleInfo:
                        Object.keys(vehicleInfoToCommit).length === 0
                            ? this.$store.getters.vehicle
                            : vehicleInfoToCommit,
                    customerInfo: {
                        firstName: this.customerQuestions.firstName,
                        lastName: this.customerQuestions.lastName,
                    },
                },
                false
            );

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

            await this.dispatchStoreAction(
                storeActions.SAVE_PAGE_DATA,
                {
                    page: fmgPageValues.EMAIL_SMS_PAGES,
                    data: { emailOrSmsValue: this.customerQuestions.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(carsFound);
        },
        async navigateForward(carsFound) {
            // Match vehicles found to vehicles in state.
            const matchingCars = carsFound.filter(
                (car) => car.vehicle.carId === this.$store.getters.vehicle.carId
            );

            // If a different vehicle is found than the one entered and the selected glass is not available for that vehicle then navigate back to "vehicle-damage"
            // display vehicle changed alert on that page.
            if (
                this.isCarIdDifferent &&
                !this.isSelectedGlassAvailableForVehicle &&
                matchingCars.length === 1
            ) {
                this.$router.navigateWithSaving(
                    this.navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS,
                    this.$route,
                    {},
                    { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true }
                );
            } else if (matchingCars.length === 1) {
                await this.navigateForwardWithSingleCarMatch();
            } else {
                this.$router.navigateWithSaving(
                    this.navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_VEHICLES,
                    this.$route,
                    {},
                    {},
                    carsFound
                );
            }
        },
        resetWarningsAndErrors() {
            this.displayVinNotFoundAlert = false;
            this.displayNonServiceableZipAlert = false;
            this.displayMatchedDifferentVehicleAlert = false;
            this.displayVinLookupByHomeAddressNotAllowedAlert = false;
        },
    },
    mounted() {
        this.attachCustomEvents();
    },
    computed: {
        AlertNonServiceableZipHeader() {
            const zipCode = this.serviceZipCode
                ? this.serviceZipCode
                : this.customerQuestions.addressQuestions.zipCode;
            const text = this.getCmsContent(
                "AlertNonServiceableZipWidget",
                "HeadlineText"
            ).replaceAll("{custom:serviceZip}", zipCode);
            return text;
        },
        AlertNonServiceableZipBody() {
            return this.getCmsContent("AlertNonServiceableZipWidget", "BodyText");
        },
        AlertMatchedDifferentVehicleHeader() {
            return this.getCmsContent(
                "AlertMatchedDifferentVehicleWidget",
                "HeadlineText"
            ).replaceAll("{custom:glassText}", getDamageString());
        },
        AlertMatchedDifferentVehicleBody() {
            const vinYmmFound = `${this.customAlertData?.vehicleInfo?.year} ${this.customAlertData?.vehicleInfo?.make} ${this.customAlertData?.vehicleInfo?.model}`;
            const vinYmmExpected = `${this.$store.getters.vehicle.year} ${this.$store.getters.vehicle.make} ${this.$store.getters.vehicle.model}`;

            return this.getCmsContent("AlertMatchedDifferentVehicleWidget", "BodyText")
                .replaceAll("{custom:glassText}", getDamageString())
                .replaceAll("{custom:vinYmmFound}", vinYmmFound)
                .replaceAll("{custom:vinYmmExpected}", vinYmmExpected);
        },
    },
    watch: {
        customerQuestions: {
            handler(newValue) {
                // if they modify one of the lookup fields (address, city, state, zipCode, or lastName), then modify the button text back to "Get my personalized quote"
                this.$refs.navbar.updateButtonText(
                    this.getCmsContent("FunnelFooterWidget", "ForwardButtonText")
                );
                this.showServiceZipField = false;
                this.resetWarningsAndErrors();
            },
            deep: true,
        },
        serviceZipCode: {
            handler(newValue) {
                // If they modify the service zip code, then hide the error message.
                this.displayNonServiceableZipAlert = false;
            },
        },
        showServiceZipField: {
            handler(newValue) {
                // If the Service Zip Code field is ever hidden, clear out it's value
                if (!newValue) {
                    this.serviceZipCode = null;
                }
            },
        },
    },
    components: {
        funnelHeader,
        navbar,
        funnelSubHeader,
        customerQuestions,
        textboxQuestion,
        alert,
        Form,
    },
};
</script>
