<template>
  <transition
      name="fade"
      mode="out-in">
      <div
          v-if="isDisplayed"
          class="shop-question"
          aria-live="polite">
          <alert
              v-if="displayDropoffInformation"
              ref="alertDropoffInformation"
              class="mb-4 drop-off-alert"
              cmsWidgetName="AlertDropoffInformationWidget"
              alertClass="alert-info"
              :isDismissible="false" />
          <buttonQuestion
              ref="buttonQuestion"
              v-model="selectedProviderNumber"
              buttonTypeString="shopListButton"
              :buttonTypeObject="shopListButton"
              class="radioQuestion"
              :questionText="questionText"
              :answers="answers"
              groupName="chooseShop"
              textPosition="text-start"
              isRequired
              validationRules="option-required"
              :additionalButtonData="additionalButtonData" />
          <textLink
              v-show="displaySeeMoreLocationsLink"
              id="showMoreShopsId"
              ref="showMoreShopsLink"
              class="show-more-shops-link"
              cmsWidgetName="ShowMoreShopsLinkWidget"
              linkType="text"
              :text="showMoreShopsLinkText"
              href="#!"
              :aria-label="showMoreShopsLinkText"
              @clickEvent="getNextShopsFromList" />
      </div>
  </transition>
</template>

<script>
// Components
import alert from '@/ux-components/alert/alert.vue';
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
import textLink from '@/ux-components/text-link/text-link.vue';

// Supporting files
import { AppointmentTypeStrings } from '@/constants/schedule-constants.js';
import baseMixin from '@/mixins/base-mixin.js';
import { defineRule } from 'vee-validate';
import { required } from '@/helpers/validation-rules';
import errorMessages from '@/constants/error-messages';
import { useMainStore } from '@/store/index.js';
import { markRaw, nextTick } from 'vue';
import { getAvailabilityRating } from '@/helpers/service-location-helper';
import shopListButton from '@/iss-components/shop-list-button/shop-list-button.vue';

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

export default {
    name: 'shop-question',
    components: {
        alert,
        buttonQuestion,
        textLink
    },
    mixins: [baseMixin],
    props: {
        modelValue: {
            type: Object,
            default: () => null
        },
        selectedAppointmentType: String,
        cmsWidgetName: String,
        validationRules: String,
        isDisplayed: Boolean
    },
    emits: ['update:modelValue', 'updatedMobileProviderNumber'],
    data() {
        return {
            shopProviders: [],
            shopListButton: markRaw(shopListButton),
            answers: [],
            shopIndex: 0,
            displaySeeMoreLocationsLink: false
        };
    },
    computed: {
        questionText() {
            return this.getCmsContent(this.cmsWidgetName, 'QuestionText');
        },
        selectedValue: {
            get() {
                return this.modelValue;
            },
            set(newValue) {
                this.$emit('update:modelValue', newValue);
            }
        },
        selectedProviderNumber: {
            get() {
                return this.selectedValue?.providerNumber;
            },
            set(newValue) {
                // Button Question only supports Number, or String data types so we must get the full object to emit
                this.selectedValue = this.getSelectedProviderObject(newValue);
            }
        },
        displayDropoffInformation() {
            return this.selectedAppointmentType === 'Dropoff';
        },
        showMoreShopsLinkText() {
            return this.getCmsContent('ShowMoreShopsLinkWidget', 'Text');
        },
        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: this.selectedAppointmentType
            };
        }
    },
    watch: {
        selectedAppointmentType: {
            async handler(newValue) {
                this.resetAnswers();

                await nextTick();

                this.selectedProviderNumber = null;

                await nextTick();

                if (newValue !== AppointmentTypeStrings.MOBILE && newValue !== AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) {
                    this.getNextShopsFromList();
                }
            }
        },
        shopProviders: {
            async handler(newValue) {
                await nextTick();

                if (this.selectedAppointmentType) {
                    const selectedShopIndex = this.getSelectedProviderIndex(
                        newValue,
                        this.selectedProviderNumber
                    );

                    if (selectedShopIndex >= 3) {
                        await this.getNextShopsFromList(selectedShopIndex + 1);
                    } else {
                        await this.getNextShopsFromList();
                        await nextTick();
                    }
                }
            }
        }
    },
    methods: {
        loadInitialData(serviceZipCode) {
            return this.loadData(serviceZipCode);
        },
        loadData(serviceZipCode) {
            return useMainStore().getProviders(serviceZipCode);
        },
        initializeComponent(shopQuestionInitialData) {
            this.shopProviders = shopQuestionInitialData.shopProviders;
        },
        async getNextShopsFromList(numberToGet = 3) {
            const shopIterator = (array, n) => {
                const l = array.length;
                return () => {
                    const end = this.shopIndex + n;
                    const part = array.slice(this.shopIndex, end);
                    this.shopIndex = end < l ? end : this.shopProviders.length;
                    return part;
                };
            };

            const toTitleCase = (str) => str.replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase());

            const nextShop = shopIterator(this.shopProviders, numberToGet);

            // Map API result data
            const mappedData = nextShop().map((shopProvider) => {
                const streetAddress = toTitleCase(shopProvider.address.streetAddress);
                const city = toTitleCase(shopProvider.address.city);
                const { state } = shopProvider.address;
                const { zipCode } = shopProvider.address;
                const distanceInMiles = Math.round(shopProvider.distanceInMiles * 2) / 2;

                return {
                    buttonLabel: city,
                    buttonLabelSubCopy: `${distanceInMiles} mi`,
                    buttonBodyCopy: `${streetAddress}, ${city}, ${state} ${zipCode}`,
                    value: shopProvider.providerNumber
                };
            });

            if (this.answers.length === 0) {
                this.answers = mappedData;
            } else {
                mappedData.forEach((shop) => {
                    this.answers.push(shop);
                });
            }

            await nextTick();

            if (this.shopIndex === this.shopProviders.length) {
                this.displaySeeMoreLocationsLink = false;
            } else {
                this.displaySeeMoreLocationsLink = true;
            }

            await nextTick();

            this.scrollToPageBottom();
        },
        resetAnswers() {
            this.answers = [];
            this.shopIndex = 0;
        },
        async reloadShopData(serviceZipCode) {
            const result = await this.loadData(serviceZipCode);
            this.initializeComponent(result.data);

            if (result.data?.mobileProviderNumber
                && (this.selectedAppointmentType === AppointmentTypeStrings.MOBILE
                    || this.selectedAppointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP)) {
                this.$emit('updatedMobileProviderNumber', result.data.mobileProviderNumber);
            }

            this.resetAnswers();

            await nextTick();
            await this.getNextShopsFromList();
        },
        getSelectedProviderObject(providerNumber) {
            const provider = this.shopProviders?.find((p) => p.providerNumber === providerNumber);
            return provider;
        },
        getSelectedProviderIndex(providers, selectedProviderNumber) {
            const index = providers.findIndex((p) => p.providerNumber === selectedProviderNumber);
            return index;
        }
    }
};
</script>

<style lang="scss">
@import "@/styles/ux-variables-svg-strings.scss";

.shop-question {
  margin-top: 1rem;
  text-align: center;

  .button-question {
      .question-text {
          margin-top: 0.5rem;
      }
  }

  .drop-off-alert {
    background-image: url($svg-drop-off-alert);
    background-repeat: no-repeat;
    background-size: 0.75rem;
    background-position: 0.5rem 0.75rem;
    border-radius: 0.5rem;
    display: flex;
    flex-direction: row;
    padding: 0.5rem 0.5rem 0.5rem 1.5rem !important;
    gap: 0.25rem;

    .alert-heading {
        text-align: left;
        font-size: 0.75rem;
        line-height: 1.25rem;
    }
    }
}
</style>
