import { storeActions } from "@/constants/store-actions";
import {
    getDeviceIdValue,
    getSessionIdValue,
    getSessionKeyValue,
    getUserIdValue,
    regenerateDeviceId,
    regenerateUserId,
    refreshSessionExpiration,
    areAllSessionCookiesSet,
    setSessionIdIfUnset,
    setSessionKeyIfUnset,
    getskeyValue,
} from "@/helpers/heritage-integration/cookie-helper";
import { queryStrings } from "@/constants/query-strings";
import { experimentSettings, experimentUniverses } from "@/constants/experiments";
import experimentMixin from "@/mixins/experiment-mixin";
import {
    analyticsPageEvents,
    GaCategories,
    GaActions,
    GaLabels,
    GaEvents,
    ValueToLogTypes,
} from "@/constants/analytics";
import { AppointmentTypeStrings } from "@/constants/schedule-constants";
import store from "@/store";

import baseMixin from "@/mixins/base-mixin";
import { applicationConfig } from "../constants/application-config";
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
import { routeData } from "@/router/constants/routes";
import { getQuerystringParameter } from "@/helpers/querystring-helper";
import { Variables } from "../constants/analytics";
import { containsRecalParts, getRecalPartNumbers } from "@/helpers/recal-helper";
import { getAmountDue, getSubTotal, getSalesTax } from "@/helpers/pricing-helper.js";
import { partTypeStrings } from "@/constants/part-type-strings";
import router from "@/router";

export default {
    methods: {
        getPageName() {
            return getPageNameFromRouter();
        },

        async logPageView(pageEvent) {
            const currentPageName = getPageNameFromRouter();
            await this.validateSession();

            const submittedOrder = baseMixin.methods.getSubmittedOrder();
            const hasSubmittedOrder = baseMixin.methods.hasSubmittedOrder();
            const hasSubmittedOrderAtConfirmationPage =
                hasSubmittedOrder && currentPageName?.toLowerCase() == routeData.CONFIRMATION.name;

            const refSequenceNum = hasSubmittedOrderAtConfirmationPage
                ? submittedOrder.referralSequenceNumber
                : store.getters.order.referralSequenceNumber;

            const parentAccountNum = hasSubmittedOrderAtConfirmationPage
                ? submittedOrder.payment.parentAccountNumber
                : store.getters.order.payment.parentAccountNumber;

            var payload = {
                userId: getUserIdValue(),
                sessionKey: getSessionKeyValue(),
                pageName: currentPageName,
                sessionId: getSessionIdValue(),
                action: "",
                event: pageEvent,
                shouldUseSessionId: false,
                experimentsForUser: store.getters.applicationUser.experiments,
                referralSequenceNumber: refSequenceNum,
                parentAccountNumber: parentAccountNum,
            };

            await baseMixin.methods.dispatchStoreAction(storeActions.LOG_PAGE_VIEW, payload, false);
        },

        async logCustomEvent(category, action, label, value) {
            const currentPageName = getPageNameFromRouter();
            await this.validateSession();

            const refSequenceNum =
                store.getters.order.referralSequenceNumber ||
                store.getters.submittedOrder?.referralSequenceNumber;

            var payload = {
                userId: getUserIdValue(),
                sessionKey: getSessionKeyValue(),
                pageName: currentPageName,
                sessionId: getSessionIdValue(),
                category: category,
                action: action,
                label: label,
                value: value,
                shouldUseSessionId: false,
                experimentsForUser: store.getters.applicationUser.experiments,
                referralSequenceNumber: refSequenceNum,
                parentAccountNumber: store.getters.order.payment.parentAccountNumber,
            };

            await baseMixin.methods.dispatchStoreAction(
                storeActions.LOG_CUSTOM_EVENT,
                payload,
                false
            );
        },

        async pushEventToGA(
            category,
            action,
            label,
            pushToLogApp = false,
            valueToLogType = null,
            value = null
        ) {
            const currentPageName = getPageNameFromRouter();
            const labelToLog = getValueToLog(label, valueToLogType);

            const eventToBePushed = {
                event: GaEvents.GENERIC_EVENT,
                category: category,
                action: action,
                label: labelToLog,
                value: value ?? undefined,
                path: `/fmg/${currentPageName}`,
            };

            pushToDataLayerIfDefined(eventToBePushed);

            if (pushToLogApp) {
                await this.logCustomEvent(category, action, labelToLog, undefined);
            }
        },

        async logDigitalConsumer() {
            const currentPageName = getPageNameFromRouter();
            const universes = store.getters.applicationUser.experiments;

            const variationNames = universes
                .filter((item) => item.universeName === experimentUniverses.CONCEPT_FUNNEL)
                .map((item) => item.variationName)
                .filter(Boolean); // removes undefined/null

            const conceptVariation = variationNames.length > 0 ? variationNames[0] : "";

            const isConceptExposed = universes.find(
                (item) => item.universeName === experimentUniverses.CONCEPT_FUNNEL
            )?.isExposed;

            const submittedOrder = baseMixin.methods.getSubmittedOrder();
            const hasSubmittedOrder = baseMixin.methods.hasSubmittedOrder();
            const hasSubmittedOrderAtConfirmationPage =
                hasSubmittedOrder && currentPageName?.toLowerCase() == routeData.CONFIRMATION.name;

            var payload = {
                actionName: `Browser page:${currentPageName}`,
                referralSequenceNumber: hasSubmittedOrderAtConfirmationPage
                    ? submittedOrder.referralSequenceNumber
                    : store.getters.order.referralSequenceNumber,
                referralNumber: hasSubmittedOrderAtConfirmationPage
                    ? submittedOrder.referralNumber
                    : store.getters.order.referralNumber,
                workOrderId: hasSubmittedOrderAtConfirmationPage
                    ? submittedOrder.workOrderId
                    : store.getters.order.workOrderId,
                workOrderNumber: hasSubmittedOrderAtConfirmationPage
                    ? submittedOrder.workOrderNumber
                    : store.getters.order.workOrderNumber,
                conceptVariation: conceptVariation,
                isConceptExposed: isConceptExposed,
            };

            await baseMixin.methods.dispatchStoreAction(
                storeActions.LOG_DIGITALCONSUMER,
                payload,
                false
            );
        },

        async pushEventForChatsToGA(category, action, label, pushToLogApp = false) {
            const currentPageName = getPageNameFromRouter();
            const value = `2.0_${currentPageName}`;
            await this.pushEventToGA(category, action, label, pushToLogApp, null, value);
        },

        async pushVariableToDataLayer(data) {
            pushToDataLayerIfDefined(data);
        },

        async pushPageViewToGA() {
            const currentPageName = getPageNameFromRouter();
            const pageViewEvent = {
                event: GaEvents.PAGE_VIEW_EVENT,
                pagePath: `/fmg/${currentPageName}`,
                pageTitle: currentPageName,
            };

            pushToDataLayerIfDefined(pageViewEvent);

            await this.logPageView(analyticsPageEvents.ENTRY);
        },

        // This sends session data to the session logging endpoint on the analytics service.
        // From there, it uses aws kinesis data stream, DigitalConsumer-Session-Data-Stream,
        // and aws FireHose stream, DigitalConsumer-Session-Firehose, to push data to an
        // S3 bucket, safelite-dev-digitalconsumer-session-data-us-east-2/1.
        // This bucket data is then picked up by snowflake for analytics use.
        async pushFmgSessionData() {
            const hasSubmittedOrder = baseMixin.methods.hasSubmittedOrder();
            const submittedOrder = baseMixin.methods.getSubmittedOrder();
            const order = hasSubmittedOrder ? submittedOrder : store.getters.order;

            const hasSubmittedApplicationUser = baseMixin.methods.hasSubmittedApplicationUser();
            const submittedApplicationUser = baseMixin.methods.getSubmittedApplicationUser();
            const applicationUser = hasSubmittedApplicationUser
                ? submittedApplicationUser
                : store.getters.applicationUser;

            const isEarlyBird = order?.lineItems?.supportingItems?.find(
                (lineItem) => lineItem.partType == partTypeStrings.EARLY_BIRD
            );

            const promoCodes = Array.isArray(order?.lineItems?.promos)
                ? order?.lineItems?.promos
                      .map((item) => item.promoCode)
                      .filter((code) => code)
                      .join(", ")
                : null;

            const glassProducts = order?.damage?.glassToReplace?.map(
                (part) => `${part.glassLocation}-${part.glassName}`
            );

            var appointment = `${order?.schedule?.date ?? ""} ${order?.schedule?.startTime ?? ""}`;

            var sessionData = {};
            sessionData.currentPage = getPageNameFromRouter();
            sessionData.sid = getSessionIdValue();
            sessionData.deviceId = getDeviceIdValue();
            sessionData.fmgSessionId = applicationUser?.savedSessionId;
            sessionData.skey = getskeyValue().toString();
            sessionData.userId = getUserIdValue();
            sessionData.carId = order?.vehicle?.carId;
            sessionData.vehicleYear = order?.vehicle?.year;
            sessionData.vehicleMake = order?.vehicle?.make;
            sessionData.vehicleModel = order?.vehicle?.model;
            sessionData.vehicleStyle = order?.vehicle?.style;
            sessionData.hasVin = order?.vehicle?.vin ? true : false;
            sessionData.cashOrInsuranceAccountType = order?.payment?.isInsurance
                ? "Insurance"
                : "Cash";
            sessionData.damageType = order?.damage?.isRepair ? "Repair" : "Replace";
            sessionData.productType = glassProducts;
            sessionData.eon = order?.eon;
            sessionData.referralNumber = order?.referralNumber;
            sessionData.referralSequenceNumber = order?.referralSequenceNumber;
            sessionData.referralDate = order?.referralDate;
            sessionData.workOrderNumber = order?.workOrderNumber;
            sessionData.workOrderId = order?.workOrderId;
            sessionData.isPia = order?.payment?.isPia ?? false;
            sessionData.piaType = order?.payment?.piaType;
            sessionData.parentAccountNumber = order?.payment?.parentAccountNumber;
            sessionData.settledTenderAmount = order?.settledTenderAmount;
            sessionData.recalRequired = containsRecalParts(order?.lineItems);
            sessionData.recalType = getRecalPartNumbers(order?.lineItems?.glassParts);
            sessionData.serviceZipCode = order?.serviceLocation?.provider?.address?.zipCode
                ? order?.serviceLocation?.provider?.address?.zipCode
                : order?.serviceLocation?.zipCode;
            sessionData.providerCtu = order?.serviceLocation?.provider?.address?.zipCodeCtu
                ? order?.serviceLocation?.provider?.address?.zipCodeCtu
                : order?.serviceLocation?.zipCodeCtu;
            sessionData.appointmentDate = appointment;
            sessionData.serviceType = order?.serviceLocation?.appointmentType;
            sessionData.promoCodes = promoCodes;
            sessionData.hasTechnicianNotes = order?.serviceLocation?.techNotes ? true : false;
            sessionData.paymentMethod = order?.payment?.piaType;
            sessionData.isTextingOptedIn = order?.customer?.isSmsOptIn ? true : false;
            sessionData.isEarlyBird = isEarlyBird ? true : false;
            sessionData.insuranceCo = order?.policy?.insuranceCompanyName;
            sessionData.deductible = order?.policy?.currentDeductible;
            sessionData.isVerified = order?.payment?.insuranceCoverage?.isVerified ?? false;
            sessionData.coverageStatus = order?.payment?.insuranceCoverage?.coverageStatus;
            sessionData.coverageSubStatus = order?.payment?.insuranceCoverage?.coverageSubStatus;
            sessionData.isNoComp = order?.policy?.isNoComp;
            sessionData.isItac = order?.policy?.isItac;
            sessionData.subTotalPrice = getSubTotal(order?.lineItems);
            sessionData.totalPrice = getAmountDue(order?.lineItems, true);
            sessionData.userAgent = navigator.userAgent;
            sessionData.cashPriceSubTotal = order?.cashPriceSubTotal;

            await baseMixin.methods.dispatchStoreAction(
                storeActions.LOG_FMG_SESSION_DATA,
                sessionData,
                false
            );
        },

        pushOrderToDataLayer() {
            // helper check for if an object is defined (but maybe falsey)
            const isDefined = (x) => x !== null && x !== undefined;

            // Get correct order object
            const hasSubmittedOrder = baseMixin.methods.hasSubmittedOrder();
            const submittedOrder = baseMixin.methods.getSubmittedOrder();
            const order = hasSubmittedOrder ? submittedOrder : store.getters.order;

            // Begin assembling payload for data layer
            const payload = {};

            // Service Zip
            if (
                order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE &&
                isDefined(order.serviceLocation.zipCode)
            ) {
                payload.serviceZipCode = order.serviceLocation.zipCode;
            } else if (
                isDefined(order.serviceLocation.appointmentType) &&
                order.serviceLocation.appointmentType !== AppointmentTypeStrings.MOBILE &&
                isDefined(order.serviceLocation.provider.address.zipCode)
            ) {
                payload.serviceZipCode = order.serviceLocation.provider.address.zipCode;
            } else {
                payload.serviceZipCode = "";
            }

            // Damage Type
            if (isDefined(order.damage.isRepair)) {
                payload.damageType = order.damage.isRepair ? "repair" : "replace";
            } else {
                payload.damageType = "";
            }

            // Account Type
            if (isDefined(order.payment.isInsurance)) {
                payload.accountType = order.payment.isInsurance ? "insurance" : "cash";
            } else {
                payload.accountType = "";
            }

            // Promo Codes
            const promos = order.lineItems.promos ?? [];
            if (promos.length === 0) {
                payload.promoCodes = "";
            } else {
                const promoCodes = promos.map((promo) => promo.promoCode);
                const promoString = promoCodes.reduce((prev, next) => `${prev},${next}`);
                payload.promoCodes = promoString;
            }

            // Vehicle info
            if (isDefined(order.vehicle.year)) {
                // Ensure cast to string.
                payload.vehicleYear = `${order.vehicle.year}`;
            } else {
                payload.vehicleYear = "";
            }

            if (isDefined(order.vehicle.make)) {
                payload.vehicleMake = order.vehicle.make;
            } else {
                payload.vehicleMake = "";
            }

            if (isDefined(order.vehicle.model)) {
                payload.vehicleModel = order.vehicle.model;
            } else {
                payload.vehicleModel = "";
            }

            if (isDefined(order.vehicle.style)) {
                payload.vehicleStyle = order.vehicle.style;
            } else {
                payload.vehicleStyle = "";
            }

            // Glass pieces
            const glass = order.damage.glassToReplace ?? [];
            if (glass.length === 0) {
                payload.glassToReplace = "";
            } else {
                const glassNames = glass.map((g) => `${g.glassLocation}/${g.glassName}`);
                const glassString = glassNames.reduce((prev, next) => `${prev},${next}`);

                payload.glassToReplace = glassString;
            }

            //EON
            if (order.eon) {
                payload.eon = order.eon;
            } else {
                payload.eon = "";
            }

            // Work Order Id
            if (order.workOrderId) {
                const parsedId = parseInt(order.workOrderId);
                if (!isNaN(parsedId)) {
                    payload.workOrderId = parsedId;
                } else {
                    payload.workOrderId = "";
                }
            } else {
                payload.workOrderId = "";
            }

            // Provider Ctu
            if (isDefined(order.serviceLocation.zipCodeCtu)) {
                payload.providerCtu = order.serviceLocation.zipCodeCtu;
            } else {
                payload.providerCtu = "";
            }

            // Work Order Number
            if (order.workOrderNumber) {
                payload.orderNumber = order.workOrderNumber;
            } else {
                payload.orderNumber = "";
            }

            // Pricing
            // Only fire for completed orders?

            const lineItems = order.lineItems ?? {};
            const combinedLineItems = [
                ...(lineItems.glassParts ?? []),
                ...(lineItems.supportingItems ?? []),
                ...(lineItems.vaps ?? []),
                ...(lineItems.promos ?? []),
            ];

            const isPricingAvailable =
                combinedLineItems.length > 0 &&
                combinedLineItems.every(
                    (lineItem) =>
                        isDefined(lineItem.kitPrice) &&
                        isDefined(lineItem.laborAmount) &&
                        isDefined(lineItem.sellingPrice)
                );
            const isTaxAvailable =
                isPricingAvailable &&
                combinedLineItems.every((lineItem) => isDefined(lineItem.salesTax));

            //unverified (in scenarios we don’t display the price)
            if (
                order.payment.isInsurance &&
                isDefined(order.payment.insuranceCoverage.isVerified) &&
                !order.payment.insuranceCoverage.isVerified
            ) {
                payload.priceSubTotal = "";
            }
            //deductible (in scenarios we don’t display the price)
            else if (
                order.payment.isInsurance &&
                isDefined(order.payment.insuranceCoverage.isVerified) &&
                order.payment.insuranceCoverage.isVerified &&
                isDefined(order.policy.currentDeductible) &&
                order.policy.currentDeductible >= 0 &&
                !order.policy.isItac &&
                !order.policy.isNoComp
            ) {
                payload.priceSubTotal = "";
            } else if (isPricingAvailable) {
                const subtotal = baseMixin.methods
                    .getTotalPriceOfAllLineItemsAndChildParts(combinedLineItems, false)
                    .toFixed(2);

                payload.priceSubTotal = parseFloat(subtotal);
            } else {
                payload.priceSubTotal = "";
            }

            // Cash Quote or Cash Price Sub Total
            payload.cashPriceSubTotal = order?.cashPriceSubTotal ?? "";

            //unverified (in scenarios we don’t display the price)
            if (
                order.payment.isInsurance &&
                isDefined(order.payment.insuranceCoverage.isVerified) &&
                !order.payment.insuranceCoverage.isVerified
            ) {
                payload.priceTotal = "";
            }
            //deductible (in scenarios we don’t display the price)
            else if (
                order.payment.isInsurance &&
                isDefined(order.payment.insuranceCoverage.isVerified) &&
                order.payment.insuranceCoverage.isVerified &&
                isDefined(order.policy.currentDeductible) &&
                order.policy.currentDeductible >= 0 &&
                !order.policy.isItac &&
                !order.policy.isNoComp
            ) {
                payload.priceTotal = "";
            } else if (isTaxAvailable) {
                const total = baseMixin.methods
                    .getTotalPriceOfAllLineItemsAndChildParts(combinedLineItems, true)
                    .toFixed(2);

                payload.priceTotal = parseFloat(total);
            } else {
                payload.priceTotal = "";
            }

            // Recalibration
            if (hasSubmittedOrder) {
                payload.isRecalibrationOnOrder = store.getters.isRecalibrationOnSubmittedState;
            } else {
                payload.isRecalibrationOnOrder = store.getters.isRecalibrationOnOrder;
            }

            // Appointment Type
            if (isDefined(order.serviceLocation.appointmentType)) {
                payload.appointmentType = order.serviceLocation.appointmentType;
            } else {
                payload.appointmentType = "";
            }
            //Insurance
            if (order.payment.isInsurance) {
                payload.isInsuranceVerified = order.payment.insuranceCoverage.isVerified ?? "";
                payload.insuranceCompanyName = order.policy.insuranceCompanyName ?? "";
                if (!order.payment.insuranceCoverage.isVerified) {
                    payload.isInsuranceItac = "";
                    payload.isInsuranceNoComp = "";
                } else {
                    payload.isInsuranceItac = order.policy.isItac ?? "";
                    payload.isInsuranceNoComp = order.policy.isNoComp ?? "";
                }
                if (
                    order.policy.isItac ||
                    order.policy.isNoComp ||
                    !order.payment.insuranceCoverage.isVerified
                ) {
                    payload.insuranceDeductible = "";
                } else {
                    payload.insuranceDeductible = order.policy.currentDeductible ?? "";
                }
            } else {
                payload.isInsuranceVerified = "";
                payload.insuranceDeductible = "";
                payload.isInsuranceItac = "";
                payload.isInsuranceNoComp = "";
                payload.insuranceCompanyName = "";
            }

            pushToDataLayerIfDefined(payload);
        },

        pushExperimentsToDataLayer() {
            const experiments = store.getters.applicationUser.experiments;
            experiments?.forEach((exp) => {
                // Set Google Dimension Index based on experiment settings.
                let googleDimensionIndex = 99;

                if (exp.settings[experimentSettings.GOOGLE_CUSTOM_DIMENSION_INDEX] !== undefined) {
                    googleDimensionIndex =
                        exp.settings[experimentSettings.GOOGLE_CUSTOM_DIMENSION_INDEX];
                }

                // Create object with dimension index and value.
                const experimentWithDimension = {
                    [`experimentId_${googleDimensionIndex}`]: exp.universeId,
                    [`variationId_${googleDimensionIndex}`]: exp.variationId,
                    [`experimentName_${googleDimensionIndex}`]: exp.universeName,
                    [`variationName_${googleDimensionIndex}`]: exp.variationName,
                    [`customDimension_${googleDimensionIndex}`]: `${exp.universeId}_${exp.variationId}_${exp.universeName}_${exp.variationName}`,
                };

                // Push to the data layer with the Google Custom Dimension Index.
                pushToDataLayerIfDefined(experimentWithDimension);
            });
        },

        pushProductArrayToDataLayer() {
            // Get correct order object
            const hasSubmittedOrder = baseMixin.methods.hasSubmittedOrder();
            const submittedOrder = baseMixin.methods.getSubmittedOrder();

            if (hasSubmittedOrder) {
                var lineItems = submittedOrder.lineItems ? submittedOrder.lineItems : {};

                // combine all line items
                var combinedLineItems = [
                    ...(lineItems.glassParts ?? []),
                    ...(lineItems.supportingItems ?? []),
                    ...(lineItems.vaps ?? []),
                    ...(lineItems.promos ?? []),
                ];

                //Get child parts
                combinedLineItems = flattenArray(combinedLineItems);

                var products = [];
                var discount = 0;
                var coupon = "";
                var subTotal = 0;
                for (var i = 0; i < combinedLineItems.length; i++) {
                    let part = combinedLineItems[i];
                    let productSku = part.partNumber;
                    let productType = part.partType;
                    let promoCode = part.promoCode;
                    let productPrice = baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts(
                        [part],
                        false
                    );

                    if (productSku == "DISCOUNT" || productType == "SERVICE PACKAGE DISCOUNT") {
                        if (coupon) {
                            coupon += ",";
                        }
                        if (productSku == "DISCOUNT") {
                            coupon += promoCode;
                        } else {
                            coupon += productSku;
                        }

                        discount += productPrice * -1;
                    } else {
                        products.push({
                            productType: productType,
                            productSku: productSku,
                            productPrice: productPrice.toFixed(2),
                            productQuantity: "1",
                        });
                        subTotal += productPrice;
                    }
                }
                pushToDataLayerIfDefined({
                    event: "productArray",
                    productArray: {
                        coupon: coupon,
                        discount: discount.toFixed(2),
                        subTotal: subTotal.toFixed(2),
                        products: products,
                    },
                });
            }
        },

        pushECommerceCartToDataLayer() {
            const isDefined = (x) => x !== null && x !== undefined;
            // Get correct order object
            const hasSubmittedOrder = baseMixin.methods.hasSubmittedOrder();
            const submittedOrder = baseMixin.methods.getSubmittedOrder();
            if (hasSubmittedOrder) {
                var lineItems = submittedOrder.lineItems ? submittedOrder.lineItems : {};
                var supportingItems =
                    submittedOrder.lineItems && submittedOrder.lineItems.supportingItems
                        ? submittedOrder.lineItems.supportingItems
                        : [];
                var insurance = submittedOrder.payment && submittedOrder.payment.isInsurance;
                var itac = submittedOrder.policy && submittedOrder.policy.isItac;
                var nocomp = submittedOrder.policy && submittedOrder.policy.isNoComp;

                var recalLineItem = supportingItems.filter(function (lineItem) {
                    return lineItem.partType.indexOf("RECALIBRATION") !== -1;
                });
                var disposalFee = supportingItems.filter(function (lineItem) {
                    return lineItem.partType.indexOf("DISPOSAL FEE") !== -1;
                });
                var mobileFee = supportingItems.filter(function (lineItem) {
                    return lineItem.partType.indexOf("MOBILE FEE") !== -1;
                });
                var repairFee = supportingItems.filter(function (lineItem) {
                    return lineItem.partType.indexOf("REPAIR FEE") !== -1;
                });

                var vaps =
                    submittedOrder.lineItems && submittedOrder.lineItems.vaps
                        ? submittedOrder.lineItems.vaps
                        : [];
                var wipers = vaps.filter(function (lineItem) {
                    return (
                        lineItem.partType.indexOf("FRONT WIPER") !== -1 ||
                        lineItem.partType.indexOf("REAR WIPER") !== -1
                    );
                });
                var rainRepel = vaps.filter(function (lineItem) {
                    return lineItem.partType.indexOf("RAIN REPEL") !== -1;
                });

                // Combine line items
                var combinedLineItems = [];
                if (lineItems.glassParts) {
                    combinedLineItems = combinedLineItems.concat(lineItems.glassParts);
                }
                if (recalLineItem) {
                    combinedLineItems = combinedLineItems.concat(recalLineItem);
                }
                if (disposalFee) {
                    combinedLineItems = combinedLineItems.concat(disposalFee);
                }
                if (mobileFee && !(insurance && !itac && !nocomp)) {
                    combinedLineItems = combinedLineItems.concat(mobileFee);
                }
                if (repairFee) {
                    combinedLineItems = combinedLineItems.concat(repairFee);
                }
                if (wipers) {
                    combinedLineItems = combinedLineItems.concat(wipers);
                }
                if (rainRepel) {
                    combinedLineItems = combinedLineItems.concat(rainRepel);
                }

                //Remove child Parts if any
                combinedLineItems.forEach((lineItem) => {
                    lineItem.childParts = [];
                });

                var isPricingAvailable =
                    combinedLineItems.length > 0 &&
                    combinedLineItems.every(function (lineItem) {
                        return (
                            isDefined(lineItem.kitPrice) &&
                            isDefined(lineItem.laborAmount) &&
                            isDefined(lineItem.sellingPrice)
                        );
                    });
                let subtotal = 0;
                if (isPricingAvailable) {
                    subtotal = baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts(
                        combinedLineItems,
                        false
                    );
                }
                pushToDataLayerIfDefined({
                    event: "eCommerceCart",
                    eCommerceCart: {
                        products: combinedLineItems,
                        subTotal: parseInt(subtotal),
                    },
                });
            }
        },

        pushCommissionJunctionGtmDataToDataLayer() {
            // helper check for if an object is defined (but maybe falsey)
            const isDefined = (x) => x !== null && x !== undefined;
            let repairReplace = "";
            let coupons = "";
            let refSequenceNum = "";
            let accountType = "";
            let amount = 0;
            let cjEvent = "";
            if (store.getters.applicationUser.affiliateCookies?.length > 0) {
                const affiliateCookies = store.getters.applicationUser.affiliateCookies;
                var cookieArray = [];
                affiliateCookies.forEach((item) => {
                    let cookieObject = convertCookieStringToObject(item.CookieValue);
                    cookieArray.push(cookieObject);
                });
                const sortedCookies = cookieArray.sort(
                    (a, b) =>
                        new Date(b.timestamp.replace("/", "T")) -
                        new Date(a.timestamp.replace("/", "T"))
                );
                const filteredCookie = sortedCookies?.find(
                    (x) => x.tagEvent?.length > 0 && x.batchEvent?.length > 0
                );
                if (isDefined(filteredCookie)) {
                    cjEvent = filteredCookie.tagEvent;
                    const hasSubmittedOrder = baseMixin.methods.hasSubmittedOrder();
                    const submittedOrder = baseMixin.methods.getSubmittedOrder();

                    if (hasSubmittedOrder) {
                        repairReplace = submittedOrder.damage.isRepair ? "Repair" : "Replace";
                        const promos = submittedOrder.lineItems.promos ?? [];
                        if (promos.length === 0) {
                            coupons = "";
                        } else {
                            const promoCodes = promos.map((promo) => promo.promoCode);
                            const promoString = promoCodes.reduce(
                                (prev, next) => `${prev}_${next}`
                            );
                            coupons = promoString;
                        }
                        const serviceZipPackage = submittedOrder.lineItems?.supportingItems?.find(
                            (x) => x.partType == "SERVICE PACKAGE DISCOUNT"
                        );
                        if (isDefined(serviceZipPackage)) {
                            if (coupons) {
                                coupons += ",";
                            }
                            coupons += serviceZipPackage.partNumber;
                        }
                        refSequenceNum = submittedOrder.referralSequenceNumber;

                        if (isDefined(submittedOrder.payment.isInsurance)) {
                            accountType = submittedOrder.payment.isInsurance ? "insurance" : "cash";
                        } else {
                            accountType = "";
                        }
                        const lineItems = submittedOrder.lineItems ?? {};
                        const combinedLineItems = [
                            ...(lineItems.glassParts ?? []),
                            ...(lineItems.supportingItems ?? []),
                            ...(lineItems.vaps ?? []),
                            ...(lineItems.promos ?? []),
                        ];

                        const isPricingAvailable =
                            combinedLineItems.length > 0 &&
                            combinedLineItems.every(
                                (lineItem) =>
                                    isDefined(lineItem.kitPrice) &&
                                    isDefined(lineItem.laborAmount) &&
                                    isDefined(lineItem.sellingPrice)
                            );
                        if (accountType == "cash" && isPricingAvailable) {
                            amount = baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts(
                                combinedLineItems,
                                false
                            );
                        }
                    }
                }
            }
            pushToDataLayerIfDefined({
                event: "commissionJunctionGtmData",
                commissionJunctionGtmData: {
                    cj_commission_junction_event: cjEvent,
                    cj_referral_sequence_number: refSequenceNum,
                    cj_amount: amount.toFixed(2),
                    cj_repair_replace: repairReplace,
                    cj_coupon: coupons,
                },
            });
        },

        pushPageErrorToDataLayer(error) {
            pushToDataLayerIfDefined({
                event: "page-error",
                error: error,
            });
        },

        prependActionToMethod(object, method, actionToPrepend) {
            const baseMethodName = method.name.startsWith("bound ")
                ? method.name.substring(6)
                : method.name;
            const baseMethod = object[baseMethodName];
            object[baseMethodName] = function () {
                actionToPrepend.apply(this, arguments);
                return baseMethod.apply(object, arguments);
            };
        },

        async initSession() {
            regenerateDeviceId();
            regenerateUserId();

            const userId = getUserIdValue(); // cookieNames.FUNNEL_USER_ID
            const deviceId = getDeviceIdValue(); // cookieNames.DXDEV
            const sessionId = getSessionIdValue(); // cookieNames.SESSION_ID
            const userAgent = navigator.userAgent; // navigator.userAgent
            const referrer =
                applicationConfig.CURRENT_ENVIRONMENT != "Localhost" ? document.referrer : null; // see above

            const payload = {
                userId: userId,
                deviceId: deviceId,
                sessionId: sessionId,
                userAgent: userAgent,
                referrer: referrer,
            };

            const response = await baseMixin.methods.dispatchStoreAction(
                storeActions.INITIALIZE_SESSION,
                payload,
                false
            );

            if (response?.data) {
                if (response.data.sessionKey) {
                    setSessionKeyIfUnset(response.data.sessionKey);
                }

                if (response.data.sessionId) {
                    setSessionIdIfUnset(response.data.sessionId);
                }
            }
        },

        noSession() {
            return !areAllSessionCookiesSet();
        },

        // sessionExpired is true when one of the analytics cookies(sid, dxdev) has expired but we still have the vehicle year in vuex
        sessionExpired() {
            const fromHeritage = getQuerystringParameter(queryStrings.FROM_HERITAGE) === "true";
            if (this.noSession() && !fromHeritage && store.getters.order.vehicle?.year > 0) {
                return true;
            } else {
                return false;
            }
        },

        async validateSession() {
            // do not init session if it is expired.  let the click event on nav-bar handle session expired logic
            if (this.sessionExpired()) {
                return;
            }

            if (this.noSession()) {
                await this.initSession();
            }

            refreshSessionExpiration();
        },

        removeParamsFromEndpoint(endpoint) {
            const endpointWithoutParams = endpoint.split("?")[0];
            const numSlashesBeforeParams = 6;
            let splitString = endpointWithoutParams.split("/");
            if (splitString.length > numSlashesBeforeParams) {
                splitString = splitString.slice(0, numSlashesBeforeParams);
                return splitString.join("/");
            } else {
                return endpointWithoutParams;
            }
        },
    },
    computed: {
        analyticsPageEvents() {
            return analyticsPageEvents;
        },
        GaCategories() {
            return GaCategories;
        },
        GaActions() {
            return GaActions;
        },
        GaLabels() {
            return GaLabels;
        },
        ValueToLogTypes() {
            return ValueToLogTypes;
        },
        Variables() {
            return Variables;
        },
    },
};

function pushToDataLayerIfDefined(data) {
    if (window.dataLayer !== undefined) {
        window.dataLayer.push(data);
    }
}

function getPageNameFromRouter() {
    if (
        router &&
        router.currentRoute &&
        router.currentRoute.value &&
        router.currentRoute.value.name
    ) {
        return router.currentRoute.value.name;
    }
}

function getValueToLog(value, valueToLogType) {
    if (valueToLogType != null && valueToLogType === ValueToLogTypes.LAST_5) {
        return value.slice(-5);
    }
    return value;
}

function flattenArray(arr) {
    let result = [];
    arr.forEach((item) => {
        result.push(item);
        if (item.childParts) {
            result = result.concat(item.childParts);
            delete item.childParts; // Remove childParts after flattening
        }
    });
    return result;
}

function convertCookieStringToObject(cookieValue) {
    const cookieObject = cookieValue.split("&").reduce((acc, pair) => {
        const [key, value] = pair.split("=");
        acc[key] = value;
        return acc;
    }, {});
    return cookieObject;
}
