<template>
    <transition
        name="fade"
        mode="out-in">
        <div
            class="shop-address"
            aria-live="polite">
            <div class="address-header">
                {{ questionText }}
            </div>
            <div
                v-if="modelValue"
                class="current-address">
                <div class="address-line">
                    <span class="shop-name">{{ displayedShopName }}</span>
                    <span class="shop-distance">{{ modelValue.distanceInMiles?.toFixed(2) }} mi</span>
                </div>
                <div class="address-line">
                    {{ getProviderAddress(modelValue) }}
                </div>
                <div class="address-line">
                    {{ getProviderCityZipState(modelValue) }}
                </div>
            </div>
            <div
                v-else
                class="no-shops-found">
                {{ `No shops found within 100 miles of ${internalZipcode}` }}
            </div>
            <buttonMain
                class="more-shops-button"
                :buttonText="showMoreShopsLinkText"
                :variant="'primary'"
                @clickEvent="openModal" />
            <alert
                v-if="modelValue?.distanceInMiles > 30"
                ref="alertShopDistance"
                class="alert-shop-distance"
                cmsWidgetName="AlertShopDistanceWidget"
                alertClass="alert-warning" />
            <modal
                :ref="modalName"
                :headerText="modalHeaderText"
                :onModalOpenedCallback="onModalOpened"
                :footerButtonText="modalFooterText"
                :modalPosition="modalPositions.center"
                :allowInvalidSubmit="true"
                @footerButtonEvent="updateSelectedProvider">
                <googleMap
                    id="map"
                    class="mb-4"
                    :markers="providerAddresses"
                    :zipCode="internalZipcode" />
                <dropdownQuestion
                    ref="searchRadiusQuestion"
                    v-model="searchRadiusInMiles"
                    inputId="searchRadiusDropdown"
                    :cmsWidgetName="searchRadiusQuestionWidgetName"
                    :variant="dropdownVariants.compact"
                    :options="searchRadiusOptions" />
                <buttonQuestion
                    ref="shopListButtonQuestion"
                    v-model="internalProviderNumber"
                    buttonTypeString="shopListButton"
                    :buttonTypeObject="shopListButton"
                    class="radioQuestion"
                    :answers="nearbyShopsData"
                    groupName="chooseShop"
                    textPosition="text-start"
                    isRequired
                    validationRules="option-required"
                    :additionalButtonData="additionalButtonData" />
                <span class="service-zip-prompt">
                    {{ serviceZipPrompt }}
                </span>
                <serviceZipQuestion
                    v-if="renderServiceZip"
                    :ref="SERVICE_ZIP_QUESTION_REF_NAME"
                    v-model="internalZipcode"
                    customInputId="serviceZipCode"
                    :cmsWidgetName="textboxQuestionWidgetName" />
                <div
                    v-if="errorMessage"
                    ref="errorMessageDiv"
                    class="row my-1 form-test-error">
                    <span
                        class="d-inline-flex mt-0"
                        role="alert">{{ errorMessage }}</span>
                </div>
            </modal>
        </div>
    </transition>
</template>

<script>
// Components
import alert from '@/ux-components/alert/alert.vue';
import buttonMain from '@/ux-components/button-main/button-main.vue';
import modal from '@/digital-components/modal/modal.vue';
import serviceZipQuestion from '@/layouts/schedule-page/service-location/service-zip-question/service-zip-question.vue';
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
import shopListButton from '@/iss-components/shop-list-button/shop-list-button.vue';
import dropdownQuestion from '@/digital-components/dropdown-question/dropdown-question.vue';
import googleMap from '@/iss-components/google-map/google-map.vue';

// Supporting files
import baseMixin from '@/mixins/base-mixin.js';
import { toTitleCase } from '@/helpers/text-helper.js';
import { markRaw } from 'vue';
import { getAvailabilityRating } from '@/helpers/service-location-helper';
import { useMainStore } from '@/store';
import widgetFields from '@/constants/cms-widget-fields';
import { dropdownVariants, modalPositions } from '@/constants/component-variants';
import errorMessages from '@/constants/error-messages';
import { defineRule } from 'vee-validate';
import { required } from '@/helpers/validation-rules';

defineRule('option-required', required(errorMessages.PROVIDER_REQUIRED));

const SERVICE_ZIP_QUESTION_REF_NAME = 'serviceZipCodeQuestion';

export default {
    name: 'shop-address',
    components: {
        alert,
        buttonMain,
        modal,
        serviceZipQuestion,
        buttonQuestion,
        dropdownQuestion,
        googleMap
    },
    mixins: [baseMixin],
    props: {
        modelValue: {
            type: Object,
            default: () => null
        },
        serviceZipcode: String,
        cmsWidgetName: String,
        validationRules: String,
        modalWidgetName: String,
        selectedAppointmentType: String
    },
    emits: ['update:modelValue', 'zip-updated'],
    data() {
        return {
            toTitleCase,
            serviceZipCodeTextInputId: '',
            internalZipcode: this.serviceZipcode,
            internalProviderNumber: this.modelValue?.providerNumber,
            searchRadiusQuestionWidgetName: 'SearchRadiusQuestionWidget',
            textboxQuestionWidgetName: 'ChangeLocationZipQuestionWidget',
            shopListButton: markRaw(shopListButton),
            searchRadiusInMiles: '25',
            nearbyShops: [],
            modalPositions,
            dropdownVariants,
            renderServiceZip: true,
            errorMessage: '',
            openingModal: false,
            SERVICE_ZIP_QUESTION_REF_NAME
        };
    },
    computed: {
        questionText() {
            return this.getCmsContent(this.cmsWidgetName, widgetFields.INPUT_QUESTION_WIDGET.QUESTION_TEXT);
        },
        showMoreShopsLinkText() {
            return this.getCmsContent('ShowMoreShopsLinkWidget', widgetFields.TEXT_BLOCK_WIDGET.TEXT);
        },
        displayedShopName() {
            if (this.modelValue.isSafeliteShop) {
                return this.getCmsContent('SafeliteShopNameWidget', widgetFields.TEXT_BLOCK_WIDGET.TEXT);
            }
            return toTitleCase(this.modelValue.companyName);
        },
        modalHeaderText() {
            // eslint-disable-next-line max-len
            return this.getCmsContent(this.modalWidgetName, widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT).replaceAll('{custom:serviceZipcode}', this.internalZipcode);
        },
        modalFooterText() {
            return this.getCmsContent(this.modalWidgetName, widgetFields.CONTENT_GROUP_WIDGET.FOOTER_TEXT);
        },
        modalName() {
            return this.modalWidgetName;
        },
        additionalButtonData() {
            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];

            return {
                displayAvailabilityIndicators: true,
                availabilityRatingCallback: getAvailabilityRating,
                startDate: formattedStartDate,
                endDate: formattedEndDate,
                shopAppointmentType: 'InshopOrDropoff'
            };
        },
        serviceZipPrompt() {
            return this.getCmsContent(this.modalWidgetName, widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT_2);
        },
        nearbyShopsData() {
            return this.nearbyShops.map((shopProvider) => {
                const city = toTitleCase(shopProvider.address.city);
                const distanceInMiles = shopProvider.distanceInMiles.toFixed(2);

                return {
                    buttonLabel: city,
                    buttonLabelSubCopy: `${distanceInMiles} mi`,
                    buttonBodyCopy: this.getFullProviderAddress(shopProvider),
                    value: shopProvider.providerNumber
                };
            });
        },
        searchRadiusArray() {
            const options = this.getCmsContent(this.searchRadiusQuestionWidgetName, widgetFields.INPUT_QUESTION_WIDGET.ANSWERS);
            return options;
        },
        searchRadiusOptions() {
            const optionsObj = {};
            if (this.searchRadiusArray) {
                this.searchRadiusArray.forEach((option) => {
                    optionsObj[option.Name] = option.Text;
                });
            }
            return optionsObj;
        },
        providerAddresses() {
            return this.nearbyShops?.map((provider) => ({
                title: toTitleCase(provider.companyName),
                fullAddress: this.getFullProviderAddress(provider),
                addressLines: [this.getProviderAddress(provider), this.getProviderCityZipState(provider)]
            })) ?? [];
        }
    },
    watch: {
        async internalZipcode() {
            if (this.openingModal) {
                return;
            }
            const shopsUpdated = await this.updateShops();
            if (shopsUpdated) {
                await this.$nextTick();
                this.$refs[SERVICE_ZIP_QUESTION_REF_NAME].internalZipcode = '';
            }
        },
        async searchRadiusInMiles() {
            if (this.openingModal) {
                return;
            }
            await this.updateShops();
        }
    },
    methods: {
        // eslint-disable-next-line consistent-return
        async updateShops(autoExpand = false) {
            this.errorMessage = '';
            let result = await this.getNearbyShops(this.searchRadiusInMiles);
            let currentSearchIndex = this.searchRadiusArray.findIndex((option) => option.Name === this.searchRadiusInMiles);
            while (autoExpand && result.length === 0 && currentSearchIndex < this.searchRadiusArray.length - 1) {
                const newSearchRadius = this.searchRadiusArray[currentSearchIndex + 1].Name;
                // eslint-disable-next-line no-await-in-loop
                result = await this.getNearbyShops(newSearchRadius);
                currentSearchIndex += 1;
            }
            if (result.length === 0) {
                this.errorMessage = errorMessages.ZIP_CODE_NOT_SERVICED_FOR_VEHICLE;
            } else {
                if (!result.find((shop) => shop.providerNumber === this.internalProviderNumber)) {
                    this.internalProviderNumber = '';
                    await this.$nextTick();
                }
                this.nearbyShops = result;
                this.searchRadiusInMiles = this.searchRadiusArray[currentSearchIndex].Name;
                return true;
            }
        },
        openModal() {
            this.$refs[this.modalName].openModal();
        },
        closeModal() {
            this.$refs[this.modalName].closeModal();
        },
        onModalOpened() {
            this.openingModal = true;
            this.internalZipcode = this.serviceZipcode;
            this.searchRadiusInMiles = '25';
            this.nearbyShops = [];
            this.updateShops(true).then(() => {
                this.internalProviderNumber = this.nearbyShops[0]?.providerNumber;
            }).finally(() => {
                this.$nextTick().then(() => {
                    this.openingModal = false;
                });
            });
            this.forceServiceZipRerender();
        },
        async updateSelectedProvider() {
            const selectedShop = this.nearbyShops.find((shop) => shop.providerNumber === this.internalProviderNumber);
            if (selectedShop) {
                this.$emit('update:modelValue', selectedShop);
                this.$emit('zip-updated', this.internalZipcode);
                this.closeModal();
            }
        },
        async getNearbyShops(radiusInMiles) {
            const result = await useMainStore().getProviders(this.internalZipcode, radiusInMiles);
            return result.data.shopProviders;
        },
        getFullProviderAddress(provider) {
            const addressLine1 = this.getProviderAddress(provider);
            const addressLine2 = this.getProviderCityZipState(provider);
            const joinString =
                addressLine1.length > 0 && addressLine2.length > 0 ? ', ' : '';
            return [addressLine1, addressLine2].join(joinString);
        },
        getProviderAddress(provider) {
            return toTitleCase(provider?.address?.streetAddress);
        },
        getProviderCityZipState(provider) {
            const city = toTitleCase(provider?.address?.city);
            const state = provider?.address?.state ?? '';
            const zipCode = provider?.address?.zipCode ?? '';
            let addressLine2 = '';
            if (city) {
                addressLine2 += city;
                if (state || zipCode) {
                    addressLine2 += state ? ', ' : ' ';
                }
            }
            if (state) {
                addressLine2 += state;
                addressLine2 += zipCode ? ' ' : '';
            }
            if (zipCode) {
                addressLine2 += zipCode;
            }
            return addressLine2;
        },
        forceServiceZipRerender() {
            this.renderServiceZip = false;
            this.$nextTick(() => {
                this.renderServiceZip = true;
            });
        }
    }
};
</script>

<style lang="scss" scoped>
@import "@/styles/ux-variables-svg-strings.scss";
.shop-address {
    .address-header {
        color: $black;
        font-weight: 600;
        margin-bottom: 0.625rem;
    }
    .address-line {
        display: flex;
    }
    .shop-distance {
        margin-left: auto;
    }
    .current-address {
        margin: .625rem 0;
    }
    .no-shops-found {
        font-size: .8125rem;
        margin: .75rem 0rem;
        font-weight: $font-weight-bold;
        line-height: 1.375rem;
        color: #4d4e53;
    }
    .more-shops-button {
        margin-bottom: 1.25rem;
    }
    .alert-shop-distance {
        margin-top: 2.5rem;
    }
    :deep(.modal-title) {
        font-weight: 400;
        display: block;
        width: fit-content;
    }
    .radioQuestion {
        margin-bottom: .625rem;
    }
    .service-zip-prompt {
        color: $black;
        font-weight: 600;
    }
    :deep(#map) {
        height: 27rem;
    }
    :deep(.textbox-question) {
        &.has-error {
            input.form-control {
                border: $border-input;
                &:focus {
                    border: $border-input-focus;
                }
            }
        }
        .form-label {
            font-weight: $font-weight-normal;
            color: $darker-gray;
        }
        .btn-primary {
            margin-bottom: 1.25rem;
        }
    }
}
</style>
