<template>
    <div class="promo-modal-question">
        <textLink
            id="promoLinkPromptId"
            linkType="text"
            :text="promoLinkText"
            href="javascript:void(0)"
            @click-event="openModal" />
        <modal
            :ref="modalName"
            :headerText="modalHeaderText"
            :onModalClosedCallback="onModalClosed"
            :onModalOpenedCallback="openModal"
            :footerButtonText="modalFooterText"
            @footer-button-event="addPromoCode">
            <promoQuestion
                ref="promoQuestion"
                customInputId="promoCode"
                v-model="promoCode"
                v-on="{ 'textboxQuestionEvent.inputIdAssigned': onInputIdAssigned }"
                cmsWidgetName="PromoQuestionWidget" />
            <alert
                ref="alertInvalidPromo"
                v-if="displayInvalidPromoAlert"
                v-html="errorMessage"
                class="mt-4 alert"
                cmsWidgetName="AlertInvalidPromoWidget"
                alertClass="alert-danger"
                v-bind:isDismissible="false" />
            <alert
                ref="AlertSimilarPromo"
                v-if="displaySimilarPromoAlert"
                class="mt-4 alert"
                cmsWidgetName="AlertSimilarPromoWidget"
                alertClass="alert-danger"
                v-bind:isDismissible="false" />
            <alert
                ref="alertInvalidStackingPromo"
                v-if="displayStackingPromoAlert"
                v-html="errorMessage"
                class="mt-4 alert"
                cmsWidgetName="AlertStackingPromoWidget"
                alertClass="alert-danger"
                v-bind:isDismissible="false" />
            <alert
                ref="AlertInShopPromo"
                v-if="displayInShopPromoAlert"
                v-html="errorMessage"
                class="mt-4 alert"
                cmsWidgetName="AlertInshopPromoWidget"
                alertClass="alert-danger"
                v-bind:isDismissible="false" />
            <div
                class="mt-4 d-flex align-items-center justify-content-between"
                v-for="(promoCode, i) in this.getPromoCodeList()"
                :key="i">
                <span class="applied-promo">
                    Promo code
                    <span class="promo-code">{{ promoCode }}</span>
                    applied
                </span>
                <textLink
                    ref="removeLink"
                    linkType="text"
                    :text="removeLinkText"
                    href="javascript:void(0)"
                    @click-event="removeItem(promoCode)" />
            </div>
        </modal>
    </div>
</template>
<script>
import textLink from "@/ux-components/text-link/text-link";
import promoQuestion from "@/fmg-components/promo-modal-question/promo-question/promo-question";
import modal from "@/digital-components/modal/modal";
import alert from "@/ux-components/alert/alert";
import { storeActions } from "@/constants/store-actions.js";
import {
    getVapsThatNeedToBeAddedToSatisfyPromos,
    promoErrorCodes,
    getPromoCodesFromPromoObjectsWithoutDuplicates,
    getPromoCodeWithoutBundleIdentifier,
} from "@/helpers/promotions-helper";
import { deepClone } from "@/helpers/object-helper";
import baseMixin from "@/mixins/base-mixin.js";
import { cartItemCategories } from "@/constants/cart-item-categories";
import store from "@/store";
import { mapTaxedLineItemsToStoreFormat } from "@/store";

import { partTypeStrings } from "@/constants/part-type-strings";
export default {
    name: "promo-modal-question",

    data() {
        return {
            promoCode: "",
            promoTextInputId: "",
            errorMessage: "",
            displayInvalidPromoAlert: false,
            displaySimilarPromoAlert: false,
            displayStackingPromoAlert: false,
            displayInShopPromoAlert: false,
            lineItems: deepClone(this.modelValue),
        };
    },
    props: {
        modelValue: Object,
        modalWidgetName: String,
        addableVaps: Object,
        pageName: String,
        taxPromos: {
            type: Boolean,
            required: false,
            default: true,
        },
        useDefaultCashParentAccount: {
            type: Boolean,
            required: false,
            default: false,
        },
    },
    computed: {
        promoLinkText() {
            return this.getCmsContent(this.modalWidgetName, "HeaderText");
        },
        modalHeaderText() {
            return this.getCmsContent("PromoQuestionWidget", "QuestionText");
        },
        modalFooterText() {
            return this.getCmsContent(this.modalWidgetName, "FooterText");
        },
        modalName() {
            return this.modalWidgetName;
        },
        modal() {
            return this.$refs[this.modalName];
        },
        StackPromoText() {
            return this.getCmsContent("AlertStackingPromoWidget", "HeadlineText");
        },
        PromoText() {
            return this.getCmsContent("AlertInvalidPromoWidget", "HeadlineText");
        },
        InShopPromoText() {
            return this.getCmsContent("AlertInshopPromoWidget", "HeadlineText");
        },
        removeLinkText() {
            return this.getCmsContent("RemoveCartItemTextWidget", "Text");
        },
    },
    methods: {
        resetAlerts() {
            this.displayStackingPromoAlert = false;
            this.displayInvalidPromoAlert = false;
            this.displaySimilarPromoAlert = false;
            this.displayInShopPromoAlert = false;
            this.errorMessage = "";
        },
        resetsOnPromoInput() {
            this.resetAlerts();
        },
        getPromoCodeList() {
            const promosToDisplay = getPromoCodesFromPromoObjectsWithoutDuplicates(
                this.lineItems.promos
            );
            return promosToDisplay;
        },
        getConflictingPromoCode(additionalInfo) {
            var conflictingCodes = additionalInfo?.[0];
            if (additionalInfo?.length > 1) {
                if (additionalInfo?.length > 2) conflictingCodes += ",";
                for (let i = 1; i < additionalInfo?.length - 1; i++) {
                    conflictingCodes += ` "${additionalInfo[i]},`;
                }
                conflictingCodes += `" and "${additionalInfo?.slice(-1)[0]}`;
            }
            return conflictingCodes;
        },
        onInputIdAssigned(inputId) {
            this.promoTextInputId = inputId;
        },
        openModal() {
            this.modal.openModal();
        },
        closeModal() {
            this.modal.closeModal();
        },
        onModalClosed() {
            this.resetAlerts();
            this.$emit("update:modelValue", this.lineItems);
            this.promoCode = "";
            this.modal.resetForm();
        },
        focusOnPromoInput() {
            const input = document.getElementById(this.promoTextInputId);
            input?.focus();
        },
        resetModalButtonStyle() {
            this.modal.resetButtonStyle();
        },
        async getPromoCodeData(
            promoCode,
            lineItems,
            addableVaps,
            useDefaultCashParentAccount,
            pageNameToLog = null
        ) {
            const pageName = pageNameToLog ?? this.$options?.name;
            const promoValidationResponse = await baseMixin.methods.dispatchStoreActionWithLogging(
                storeActions.VALIDATE_ORDER_PROMO_AND_SAVE_SERVER_DATA,
                {
                    promoCode: promoCode,
                    lineItemsToUse: lineItems,
                    addableVaps: addableVaps,
                    useDefaultCashParentAccount: useDefaultCashParentAccount,
                },
                pageName,
                false
            );

            return {
                isValid: !("errorCode" in promoValidationResponse),
                promoCode: promoValidationResponse?.orderPromos, // should be an array of promos
                errorCode: promoValidationResponse?.errorCode,
                additionalInfo: promoValidationResponse?.additionalInfo,
            };
        },
        async removeItem(promo) {
            this.lineItems[cartItemCategories.PROMOS] = this.lineItems[
                cartItemCategories.PROMOS
            ].filter(
                (lineItemsToKeep) =>
                    getPromoCodeWithoutBundleIdentifier(lineItemsToKeep.promoCode) != promo
            );
            await baseMixin.methods.dispatchStoreAction(
                storeActions.SAVE_ACTIVE_AND_OR_INACTIVE_PROMOS,
                {
                    activePromos: this.lineItems.promos,
                },
                false
            );
        },
        getErrorMessage(error, additionalInfo) {
            switch (error) {
                case promoErrorCodes.PROMO_STACKING_NOT_ALLOWED:
                case promoErrorCodes.SIMILAR_PROMO_ALREADY_ON_ORDER:
                    return additionalInfo.length === 1 &&
                        additionalInfo[0] === this.promoCode.toUpperCase()
                        ? (this.displaySimilarPromoAlert = true)
                        : ((this.errorMessage = this.StackPromoText?.replace(
                              /\{custom:(NEW|OLD)PROMOCODE\}/g,
                              (match, group) =>
                                  group === "NEW"
                                      ? this.promoCode.toUpperCase()
                                      : this.getConflictingPromoCode(additionalInfo)
                          )),
                          (this.displayStackingPromoAlert = true));
                case promoErrorCodes.INVALID_PROMO_ON_ORDER:
                    if (additionalInfo.some((x) => x.toUpperCase() === "APPOINTMENT_TYPE")) {
                        this.errorMessage = this.InShopPromoText?.replaceAll(
                            "{custom:INSHOPPROMOCODE}",
                            this.promoCode.toUpperCase()
                        );
                        return (this.displayInShopPromoAlert = true);
                    } else {
                        this.errorMessage = this.PromoText?.replaceAll(
                            "{custom:PROMOCODE}",
                            this.promoCode.toUpperCase()
                        );
                        return (this.displayInvalidPromoAlert = true);
                    }
                default:
                    this.errorMessage = this.PromoText?.replaceAll(
                        "{custom:PROMOCODE}",
                        this.promoCode.toUpperCase()
                    );
                    return (this.displayInvalidPromoAlert = true);
            }
        },
        async addPromoCode() {
            if (this.promoCode) {
                this.resetAlerts();

                const promoCodeData = await this.getPromoCodeData(
                    this.promoCode,
                    this.lineItems,
                    this.addableVaps,
                    this.useDefaultCashParentAccount,
                    this.pageName
                );
                if (promoCodeData.isValid) {
                    if (this.taxPromos) {
                        const pricedLineItemsToTax = [];
                        pricedLineItemsToTax.push(...promoCodeData.promoCode); // promoCodeData.promoCode should be an array
                        const taxedLineItems =
                            await baseMixin.methods.dispatchStoreActionWithLogging(
                                storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
                                {
                                    billToAccountNumber:
                                        store.getters.order.payment.billToAccountNumber,
                                    providerNumber:
                                        store.getters.order.serviceLocation.provider.providerNumber,
                                    appointmentType:
                                        store.getters.order.serviceLocation.appointmentType,
                                    serviceLocationCity: store.getters.order.serviceLocation.city,
                                    serviceLocationState: store.getters.order.serviceLocation.state,
                                    serviceLocationZipCode:
                                        store.getters.order.serviceLocation.zipCode,
                                    pricedLineItems: pricedLineItemsToTax,
                                },
                                "payment-method",
                                false
                            );

                        // Match all line items to the line items as they are in the store
                        // and rebuild the original structure.
                        this.lineItems = mapTaxedLineItemsToStoreFormat(
                            taxedLineItems,
                            this.lineItems
                        );
                        const taxedVaps = mapTaxedLineItemsToStoreFormat(
                            taxedLineItems,
                            this.addableVaps
                        );

                        const getVaps = getVapsThatNeedToBeAddedToSatisfyPromos(
                            promoCodeData.promoCode,
                            taxedVaps,
                            this.lineItems
                        );

                        this.lineItems.vaps?.push(...getVaps);
                    }
                    this.lineItems?.promos.push(...promoCodeData.promoCode);

                    this.$emit("promoAdded", this.lineItems);

                    this.closeModal();
                } else {
                    this.getErrorMessage(promoCodeData.errorCode, promoCodeData.additionalInfo);
                    this.focusOnPromoInput();
                    this.resetModalButtonStyle();
                }
            }
        },
    },
    watch: {
        promoCode() {
            this.displayInvalidPromoAlert = false;
            this.displayStackingPromoAlert = false;
            this.displaySimilarPromoAlert = false;
            this.displayInShopPromoAlert = false;
        },
        modelValue: {
            handler(newValue) {
                this.lineItems = deepClone(newValue);
            },
            deep: true,
        },
    },

    components: {
        textLink,
        promoQuestion,
        modal,
        alert,
    },
};
</script>
<style lang="scss" scoped>
.applied-promo {
    font-size: 0.875rem;
    font-weight: 500;
    line-height: 24px;
    color: $green;

    .promo-code {
        text-transform: uppercase;
    }
}
.alert {
    color: $red;
    font-size: 0.875rem;
    font-weight: 500;
    line-height: 24px;
}
</style>
