<template>
    <div class="service-location">
        <alert
            v-if="displayRecalibrationWarning"
            ref="alertRecalNoMobile"
            cmsWidgetName="AlertRecalNoMobileWidget"
            alertClass="alert-warning"
            @textLinkClicked="openModalAction" />
        <alert
            v-if="displayBigTruckNoShops"
            ref="alertBigTruckNoShops"
            cmsWidgetName="AlertBigTruckNoShopsWidget"
            alertClass="alert-warning" />
        <div class="appointment-type">
            <div class="appointment-type-question-text d-flex">
                <span
                    v-if="recalibrationRequired"
                    class="recal-text">{{ scheduleRecalText }}</span>
                <span
                    v-if="!requiresInshopRecalibration">{{ appointmentQuestionText }}</span>
            </div>
            <alert
                v-if="displayServiceableInshopOnly"
                ref="alertInshopOnly"
                cmsWidgetName="AlertInshopOnlyWidget"
                :manualCopy="inShopOnlyCopy"
                :isCollapsible="true"
                alertClass="alert-warning" />
            <alert
                v-if="displayServiceableMobileOnly"
                ref="alertMobileOnly"
                cmsWidgetName="AlertMobileOnlyWidget"
                :manualCopy="mobileOnlyCopy"
                :isCollapsible="true"
                alertClass="alert-warning" />
            <appointmentTypeQuestion
                v-if="!requiresInshopRecalibration && isServiceableMobile"
                ref="appointmentTypeQuestion"
                v-model="selectedAppointmentType"
                groupName="appointmentTypeQuestion"
                cmsWidgetName="AppointmentTypeQuestionWidget"
                validationRules="option-required" />
        </div>
        <div
            v-if="isInshop">
            <alert
                v-if="displayLowAvailabilityInshop"
                ref="alertLowAvailabilityInshop"
                cmsWidgetName="AlertLowAvailabilityInshopWidget"
                :manualHeadlineLineTwo="getLowAvailabilityHeadlineLineTwoText"
                :isCollapsible="true"
                :startCollapsed="true"
                alertClass="alert-warning">
                <template #headline-line-two>
                    <button
                        class="m-0 alert-header-text d-block looka-likea-link"
                        type="button"
                        @click="triggerShopAddressModal">
                        <span class="m-0">
                            {{ getLowAvailabilityHeadlineLineTwoText }}
                        </span>
                    </button>
                </template>
            </alert>
            <shopAddress
                ref="shopAddress"
                v-model="selectedProvider"
                :serviceZipcode="zipCode"
                :selectedAppointmentType="selectedAppointmentType"
                modalWidgetName="ChangeLocationModalWidget"
                cmsWidgetName="ShopAddressWidget"
                @zipUpdated="handleInShopZipUpdated" />
            <!-- INTEGRATION TODO: Put this right under the calendar -->
            <alert
                v-if="selectedProvider === null"
                ref="alertNoAvailableShops"
                cmsWidgetName="AlertNoAvailableShopsWidget"
                :isCollapsible="false"
                alertClass="alert-danger" />
        </div>
        <div
            v-if="isMobile">
            <div class="expandable-link-container">
                <a
                    v-if="displayMilitaryZipAlert && !militaryBaseWarningExpanded"
                    href="#"
                    class="expandable-link"
                    @click.prevent="militaryBaseWarningExpanded = true">
                    {{ militaryBaseWarningLinkText }}
                </a>
                <div
                    v-if="displayMilitaryZipAlert && militaryBaseWarningExpanded"
                    class="expandable-link-text">
                    {{ militaryBaseWarningText }}
                </div>
            </div>
            <serviceZipQuestion
                ref="mobileServiceZipCodeQuestion"
                v-model="mobileZipCode"
                customInputId="mobileServiceZipCode"
                class="mobile-service-zip-question"
                :placeholderText="mobileZipPlaceholder"
                :serviceZipFormatErrorMessage="errorMessages.MOBILE_SERVICE_ZIP_FORMAT"
                :hasError="mobileZipError !== ''"
                cmsWidgetName="MobileZipWidget" />
            <div
                v-if="mobileZipError"
                ref="errorMessageDiv"
                class="row my-1 form-test-error">
                <span
                    class="d-inline-flex mt-0"
                    role="alert">{{ mobileZipError }}</span>
            </div>
            <textBlock
                v-if="displayMobileFeeDisclaimer"
                cmsWidgetName="MobileFeeDisclaimerWidget"
                typeStyle="disclaimer" />
        </div>
        <contentGroupModal
            :ref="RECAL_MODAL_REF_NAME"
            cssModalHeadlineClass="text-center"
            cmsWidgetName="RecalModal" />
    </div>
</template>
<script>
// Import Supporting Files
import { AppointmentTypeStrings } from '@/constants/schedule-constants.js';
import errorMessages from '@/constants/error-messages';
import { useMainStore } from '@/store';
import showIssLoadingModal from '@/helpers/loading-modal-helper.js';
import {
    getAvailabilityRating,
    getServiceabilityDetails,
    getZipCodeData,
    getMobileZipCodeData
} from '@/helpers/service-location-helper';
import { toTitleCase } from '@/helpers/text-helper.js';

// Import Component
import alert from '@/ux-components/alert/alert.vue';
import textBlock from '@/digital-components/text-block/text-block.vue';
import appointmentTypeQuestion from '@/layouts/schedule-page/service-location/appointment-type-question/appointment-type-question.vue';
import baseFormMixin from '@/mixins/base-form-mixin';
import contentGroupModal from '@/iss-components/content-group-modal/content-group-modal.vue';
import shopAddress from '@/layouts/schedule-page/service-location/shop-address/shop-address.vue';
import serviceZipQuestion from '@/layouts/schedule-page/service-location/service-zip-question/service-zip-question.vue';
import widgetFields from '@/constants/cms-widget-fields';

const RECAL_MODAL_REF_NAME = 'RecalModal';

export default {
    name: 'service-location',
    components: {
        alert,
        textBlock,
        appointmentTypeQuestion,
        contentGroupModal,
        shopAddress,
        serviceZipQuestion
    },
    mixins: [baseFormMixin],
    emits: ['appointment-type-changed', 'city-updated', 'mobile-zip-updated', 'provider-changed'],
    setup() {
        const mainStore = useMainStore();
        return { mainStore };
    },
    data() {
        return {
            streetAddress: this.getServiceAddressFromStore(),
            streetAddress2: this.getServiceAddress2FromStore(),
            city: this.getServiceCityFromStore(),
            state: this.getServiceStateFromStore(),
            zipCode: this.getServiceZipCodeFromStore(),
            isGlassServiceableInshop: null,
            isRecalibrationServiceableInshop: null,
            isGlassServiceableMobile: null,
            isRecalibrationServiceableMobile: null,
            selectedAppointmentType: this.getSelectedAppointmentType(),
            selectedProvider: this.getSelectedProvider(),
            mobileFeePart: null,
            mobileProviderNumber: null,
            zipContainsMilitaryBase: false,
            zipCodeCtu: null,
            mobileZipCode: '',
            mobileZipError: '',
            militaryBaseWarningExpanded: false,
            availabilityRating: null,
            RECAL_MODAL_REF_NAME,
            errorMessages
        };
    },
    computed: {
        appointmentQuestionText() {
            return this.getCmsContent('WhereWouldYouLikeServiceWidget', widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT);
        },
        displayBigTruckNoShops() {
            return this.isBigTruck && !this.isServiceableInshop && !this.isServiceableMobile;
        },
        displayLowAvailabilityInshop() {
            return this.availabilityRating === 'low' && this.isInshop;
        },
        displayMilitaryZipAlert() {
            return this.zipContainsMilitaryBase && this.isServiceableMobile;
        },
        displayMobileFeeDisclaimer() {
            return this.mainStore.isNoComp || this.mainStore.isITAC;
        },
        displayRecalibrationWarning() {
            return this.requiresInshopRecalibration;
        },
        displayServiceableInshopOnly() {
            return !this.isServiceableMobile && this.isServiceableInshop && !this.displayRecalibrationWarning;
        },
        displayServiceableMobileOnly() {
            return this.isServiceableMobile && this.recalibrationRequired && !this.isServiceableInshop;
        },
        getLowAvailabilityHeadlineLineTwoText() {
            return 'Try a different location';
        },
        inShopOnlyCopy() {
            let content = this.getCmsContent('AlertInshopOnlyWidget', widgetFields.ALERT_WIDGET.BODY_TEXT);
            content = content.replace('{custom:city}', toTitleCase(this.city));
            return content;
        },
        isBigTruck() {
            return this.mainStore.order.vehicle.isBigTruck;
        },
        isInshop() {
            return (
                this.selectedAppointmentType === 'Inshop'
                || this.selectedAppointmentType === 'Dropoff'
            );
        },
        isMobile() {
            return this.selectedAppointmentType === AppointmentTypeStrings.MOBILE;
        },
        isServiceableInshop() {
            if (this.isRecalibrationServiceableInshop !== null) {
                return (this.isGlassServiceableInshop && this.isRecalibrationServiceableInshop);
            }

            return this.isGlassServiceableInshop;
        },
        isServiceableMobile() {
            if (this.isRecalibrationServiceableMobile !== null) {
                return (
                    this.isGlassServiceableMobile
                    && this.isRecalibrationServiceableMobile
                );
            }
            return this.isGlassServiceableMobile;
        },
        militaryBaseWarningLinkText() {
            return this.getCmsContent('AlertMilitaryBaseZipWidget', widgetFields.ALERT_WIDGET.HEADLINE_TEXT);
        },
        militaryBaseWarningText() {
            return this.getCmsContent('AlertMilitaryBaseZipWidget', widgetFields.ALERT_WIDGET.BODY_TEXT);
        },
        mobileOnlyCopy() {
            let content = this.getCmsContent('AlertMobileOnlyWidget', widgetFields.ALERT_WIDGET.BODY_TEXT);
            content = content.replace('{custom:city}', toTitleCase(this.city));
            return content;
        },
        mobileZipPlaceholder() {
            return this.getCmsContent('MobileZipPlaceHolderWidget', widgetFields.TEXT_BLOCK_WIDGET.TEXT);
        },
        recalibrationRequired() {
            return this.mainStore.hasRecalibrationPart;
        },
        requiresInshopRecalibration() {
            // Specifically check for isRecalibrationServiceableMobile === false, not null or true.
            return (
                this.isServiceableInshop
                && this.isGlassServiceableMobile
                && this.isRecalibrationServiceableMobile === false
            );
        },
        scheduleRecalText() {
            if (this.requiresInshopRecalibration) {
                return this.getCmsContent('WhereWouldYouLikeServiceWidget', widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT_2);
            }
            return this.getCmsContent('WhereWouldYouLikeServiceWidget', widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT);
        }
    },
    watch: {
        city(newCity, oldCity) {
            if (newCity !== oldCity) {
                this.$emit('city-updated', newCity);
            }
        },
        async mobileZipCode(newZip, oldZip) {
            if (newZip !== '' && newZip !== oldZip) {
                showIssLoadingModal(true);
                await this.updateMobileZip();
                const updateMobileZipServiceLocationObj = {
                    mobileProviderNumber: this.mobileProviderNumber,
                    provider: null,
                    refreshDatePicker: true,
                    zipCode: this.zipCode,
                    zipCodeCtu: this.zipCodeCtu
                };
                this.$emit('mobile-zip-updated', updateMobileZipServiceLocationObj);
            }
        },
        selectedAppointmentType(newValue, oldValue) {
            if (this.selectedAppointmentType === AppointmentTypeStrings.IN_SHOP && this.selectedProvider && this.availabilityRating === null) {
                this.refreshAvailabilityRating();

                const appointmenTypeServiceLocationObj = {
                    appointmentType: newValue,
                    mobileProviderNumber: null,
                    provider: this.selectedProvider,
                    refreshDatePicker: oldValue !== newValue && oldValue !== null,
                    resetDatePicker: oldValue !== newValue || oldValue === null,
                    zipCode: this.zipCode,
                    zipCodeCtu: this.zipCodeCtu
                };
                this.$emit('appointment-type-changed', appointmenTypeServiceLocationObj);
            } else {
                const appointmenTypeServiceLocationObj = {
                    appointmentType: newValue,
                    mobileProviderNumber: this.mobileProviderNumber,
                    provider: null,
                    refreshDatePicker: false,
                    resetDatePicker: true,
                    zipCode: this.zipCode,
                    zipCodeCtu: this.zipCodeCtu
                };
                this.$emit('appointment-type-changed', appointmenTypeServiceLocationObj);
            }
        },
        selectedProvider(newProvider, oldProvider) {
            if (newProvider?.providerNumber !== oldProvider?.providerNumber || this.availabilityRating === null) {
                const appointmentIsInshop = this.selectedAppointmentType === AppointmentTypeStrings.IN_SHOP;
                const returnedProvider = {
                    provider: newProvider,
                    refreshDatePicker: appointmentIsInshop && oldProvider?.providerNumber !== null
                };

                if (appointmentIsInshop && newProvider?.providerNumber != null) {
                    this.refreshAvailabilityRating();
                }

                if (newProvider?.providerNumber !== oldProvider?.providerNumber) {
                    this.$emit('provider-changed', returnedProvider);
                }
            }
        }
    },
    methods: {
        initializeComponent(initialData) {
            this.setData(initialData);
        },
        async forwardButtonAction() {
            let provider = this.selectedProvider;
            this.mainStore.updateMobileFee(null);
            if (this.isMobile) {
                if (this.mainStore.isNoComp || this.mainStore.isITAC) {
                    this.mainStore.updateMobileFee(this.mobileFeePart);
                }

                provider = {
                    providerNumber: this.mobileProviderNumber,
                    address: {
                        streetAddress: null,
                        city: null,
                        state: null,
                        zipCode: null,
                        zipCodeCtu: null
                    }
                };
            }

            this.mainStore.saveServiceLocation({
                address: this.streetAddress,
                address2: this.streetAddress2,
                city: this.city,
                state: this.state,
                zipCode: this.zipCode,
                zipCodeCtu: this.zipCodeCtu,
                appointmentType: this.selectedAppointmentType,
                provider
            });
        },
        openModalAction(modalName) {
            this.$refs[modalName].openModal();
        },
        resetDependentState() {},
        getServiceAddressFromStore() {
            return useMainStore().order.serviceLocation.address;
        },
        getServiceAddress2FromStore() {
            return useMainStore().order.serviceLocation.address2;
        },
        getServiceCityFromStore() {
            return useMainStore().order.serviceLocation.city;
        },
        getServiceStateFromStore() {
            return (
                useMainStore().order.serviceLocation.state
                || useMainStore().order.customer.address.state
            );
        },
        getServiceZipCodeFromStore() {
            return (
                useMainStore().order.serviceLocation.zipCode
                || useMainStore().order.customer.address.zipCode
            );
        },
        getSelectedAppointmentType() {
            return useMainStore().order.serviceLocation.appointmentType;
        },
        getSelectedProvider() {
            return useMainStore().order.serviceLocation.provider;
        },
        async handleInShopZipUpdated(newZip) {
            this.zipCode = newZip;
            const zipCodeData = await getZipCodeData(this.zipCode);
            this.city = zipCodeData.city;
            this.setCtuForMobile(zipCodeData.zipCodeCtu);
            this.setContainsMilitaryBase(zipCodeData.containsMilitaryBase);

            const serviceabilityDetailsPromise = getServiceabilityDetails(this.zipCode);
            await serviceabilityDetailsPromise.then((result) => {
                const details = result.data;
                if (details) {
                    this.setServiceabilityDetails(details);
                }
            });
        },
        refreshAvailabilityRating() {
            const startDate = new Date();
            const endDate = new Date();
            endDate.setDate(startDate.getDate() + 6);
            const formattedStartDate = startDate.toISOString().split('T')[0];
            const formattedEndDate = endDate.toISOString().split('T')[0];

            getAvailabilityRating(
                formattedStartDate,
                formattedEndDate,
                AppointmentTypeStrings.IN_SHOP,
                this.selectedProvider ? this.selectedProvider.providerNumber : null
            ).then((rating) => {
                this.availabilityRating = rating;
            }).catch(() => {
                this.availabilityRating = null;
            });
        },
        setCtuForMobile(val) {
            this.zipCodeCtu = val;
        },
        setData(initialData) {
            if (initialData.zipCodeData) {
                this.zipContainsMilitaryBase = initialData.zipCodeData.containsMilitaryBase;
                this.zipCodeCtu = initialData.zipCodeData.zipCodeCtu;
                this.city = initialData.zipCodeData.city;
            }

            if (initialData.serviceabilityDetails) {
                this.setServiceabilityDetails(initialData.serviceabilityDetails);
            }

            if (initialData.mobileFeePart) {
                this.mobileFeePart = initialData.mobileFeePart;
            }

            if (initialData.providers) {
                this.setMobileProviderNumber(initialData.providers.mobileProviderNumber);
                let foundMatch = false;
                if (this.selectedProvider && this.selectedProvider.providerNumber) {
                    // eslint-disable-next-line max-len
                    const matchedProvider = initialData.providers.shopProviders.find((provider) => provider.providerNumber === this.selectedProvider.providerNumber);
                    if (matchedProvider) {
                        foundMatch = true;
                        this.selectedProvider = matchedProvider;
                    }
                }
                if (initialData.providers.shopProviders.length > 0 && !foundMatch) {
                    // eslint-disable-next-line prefer-destructuring
                    this.selectedProvider = initialData.providers.shopProviders[0];
                } else if (initialData.providers.shopProviders.length === 0) {
                    this.selectedProvider = null;
                }
            }

            if (initialData.glassFees) {
                useMainStore().getCombinedQuote(initialData.glassFees)
                    .then((combinedQuote) => {
                        this.setGlassFeeItems(combinedQuote);
                    });
            }
        },
        setContainsMilitaryBase(val) {
            if (this.zipContainsMilitaryBase !== val) {
                this.zipContainsMilitaryBase = val;
            }
        },
        setGlassFeeItems(newGlassFeeItems) {
            this.mainStore.updateGlassFees(newGlassFeeItems);
        },
        setMobileProviderNumber(providerNumber) {
            this.mobileProviderNumber = providerNumber;
        },
        setServiceabilityDetails(serviceabilityDetails) {
            this.isGlassServiceableInshop = serviceabilityDetails.isGlassServiceableInshop;
            this.isRecalibrationServiceableInshop = serviceabilityDetails.isRecalibrationServiceableInshop;
            this.isGlassServiceableMobile = serviceabilityDetails.isGlassServiceableMobile;
            this.isRecalibrationServiceableMobile = serviceabilityDetails.isRecalibrationServiceableMobile;
            if (!this.isServiceableMobile) {
                this.selectedAppointmentType = AppointmentTypeStrings.IN_SHOP;
            }
        },
        triggerShopAddressModal() {
            this.$refs.shopAddress.openModal();
        },
        async updateMobileZip() {
            this.mobileZipError = '';
            const zipCodeData = await getMobileZipCodeData(this.mobileZipCode);

            if (!zipCodeData.isValid) {
                this.mobileZipError = errorMessages.INVALID_ZIP;
            } else if (!zipCodeData.isServiceable) {
                this.mobileZipError = errorMessages.NO_SERVICE_IN_AREA(toTitleCase(zipCodeData.city));
            } else {
                this.city = zipCodeData.city;
                this.zipCode = this.mobileZipCode;
                this.setCtuForMobile(zipCodeData.zipCodeCtu);
                this.setContainsMilitaryBase(zipCodeData.containsMilitaryBase);

                const serviceabilityDetailsPromise = getServiceabilityDetails(this.mobileZipCode);
                await serviceabilityDetailsPromise.then((result) => {
                    const details = result.data;
                    if (details) {
                        this.setServiceabilityDetails(details);
                    }
                });

                const providersPromise = useMainStore().getProviders(this.mobileZipCode);
                await providersPromise.then((result) => {
                    const providers = result.data;
                    if (providers) {
                        this.setMobileProviderNumber(providers.mobileProviderNumber);
                        if (providers.shopProviders.length > 0) {
                            // eslint-disable-next-line prefer-destructuring
                            this.selectedProvider = providers.shopProviders[0];
                        } else {
                            this.selectedProvider = null;
                        }
                    }
                });
            }
        }
    }
};
</script>

<style lang="scss" scoped>
$page-side-padding: 1.5rem;

.service-location {
    > div {
        margin-top: 1.25rem;
        margin-bottom: 0;
    }
    .form-test-error {
        font-weight: $font-weight-bold;
    }
    .appointment-type-question-text {
        color: $black;
        font-weight: 600;
        font-size: 1rem;
        line-height: 1.625rem;
        flex-direction: column;
        .recal-text {
            font-weight: $font-weight-bold;
        }
    }
    .mobile-service-zip-question {
        :deep(.input-wrapper.has-text-button) {
            button {
                background-color: #1574a1;
            }
        }
        :deep(.form-test-error span) {
            font-weight: $font-weight-bold;
        }
    }
    .expandable-link-container {
        margin-bottom: 1rem;
    }
    .expandable-link {
        font-style: italic;
        font-weight: $font-weight-bold;
        text-decoration: none;
        color: $heritage-blue-primary;
        line-height: 1.375rem;
        &:hover {
            text-decoration: underline;
        }
    }
    div.alert {
        margin-top: 0.625rem;

        :deep(.alert-header) {
            button.btn-collapse {
                display: block;
            }
        }

        button.looka-likea-link {
            background: none;
            border: none;
            font-weight: 500;
            font-size: 1rem;
            padding: 0;
            color: $heritage-blue-primary;
            text-decoration: none;
            cursor: pointer;

            &:hover {
                color: #125b7e;
                text-decoration: underline;
            }
        }
    }
}
</style>
