import {
    areAllSessionCookiesSet,
    getDeviceIdValue,
    getSessionIdValue,
    getSessionKeyValue,
    getUserIdValue,
    regenerateUserId,
    regenerateDeviceId,
    setSessionIdIfUnset,
    setSessionKeyIfUnset
} from '@/helpers/cookie-helper';
import applicationConfig from '@/constants/application-config';
import queryStrings from '@/constants/query-strings';
import { experimentSettings } from '@/constants/experiments';
import {
    analyticsPageEvents,
    GaCategories,
    GaActions,
    GaLabels,
    GaEvents,
    ValueToLogTypes
} from '@/constants/analytics';
import { getCartTotal, getSubtotal } from '@/helpers/cart-helper';
import { getRecalPartNumbers } from "@/helpers/recal-helper";
import coverageStatuses from '@/constants/coverage-statuses';
import coverageType from '@/constants/coverage-type';
import issPageValues from '@/router/router-constants/issPage-values';
import { useMainStore } from '@/store';

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

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

export default {
    methods: {
        getPageNameByQueryString() {
            const params = new URLSearchParams(location.search);

            if (params.has(queryStrings.ISS_PAGE)) {
                return params.get(queryStrings.ISS_PAGE);
            }
            return '';
        },
        logPageView(pageEvent) {
            const store = useMainStore();
            const currentPageName = this.getPageNameByQueryString();
            
            const payload = {
                userId: getDeviceIdValue(),
                sessionKey: getSessionKeyValue(),
                pageName: currentPageName,
                referralSequenceNumber: store.order.referralSequenceNumber,
                parentAccountNumber: store.order.parentAccountNumber ?? 0,
                sessionId: getSessionIdValue(),
                action: '',
                event: pageEvent,
                shouldUseSessionId: false,
                experimentsForUser: store.applicationUser.experiments
            };

            store.logPageView(payload);
        },

        logCustomEvent(category, action, label, value) {
            const store = useMainStore();
            const currentPageName = this.getPageNameByQueryString();

            const payload = {
                userId: getDeviceIdValue(),
                sessionKey: getSessionKeyValue(),
                pageName: currentPageName,
                referralSequenceNumber: store.order.referralSequenceNumber,
                parentAccountNumber: store.order.parentAccountNumber ?? 0,
                sessionId: getSessionIdValue(),
                category,
                action,
                label,
                value,
                shouldUseSessionId: false,
                experimentsForUser: store.applicationUser.experiments
            };

            store.logCustomEvent(payload);
        },

        pushEventToGA(category, action, label, pushToLogApp = false, valueToLogType = null, value = undefined) {
            const currentPageName = this.getPageNameByQueryString();
            const labelToLog = getValueToLog(label, valueToLogType);

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

            pushToDataLayerIfDefined(eventToBePushed);

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

        pushPageViewToGA() {
            const currentPageName = this.getPageNameByQueryString();
            const pageViewEvent = {
                event: GaEvents.PAGE_VIEW_EVENT,
                pagePath: `/iss/?${queryStrings.ISS_PAGE}=${currentPageName}`,
                pageTitle: currentPageName
            };

            pushToDataLayerIfDefined(pageViewEvent);

            this.logPageView(analyticsPageEvents.ENTRY);
        },

        pushValueToGA() {
            pushToDataLayerIfDefined({
                siteType: useMainStore().issConfig.siteType
            });
        },

        pushExperimentsToDataLayer() {
            const { experiments } = useMainStore().applicationUser;
            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);
            });
        },

        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);
            };
        },
        
        logDigitalConsumer() {
            const store = useMainStore();
            const currentPageName = this.getPageNameByQueryString();
            const universes = store.applicationUser.experiments;
            const deviceId = getDeviceIdValue();
            const sid = getSessionIdValue();

            const variationNames = universes
                .filter((item) => item.universeName === experimentSettings.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 === experimentSettings.CONCEPT_FUNNEL
            )?.isExposed;
            
            const submittedOrder = store.getSubmittedOrder();
            const hasSubmittedOrder = store.hasSubmittedOrder();

            // TODO: Find equivalent ISS methods for these:
            const hasSubmittedOrderAtConfirmationPage =
                hasSubmittedOrder && currentPageName?.toLowerCase() === issPageValues.ORDER_CONFIRMATION;

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

            store.logDigitalConsumer(payload);
        },
        
        // 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.
        pushIssSessionData() {
            const store = useMainStore();
            const submittedOrder = store.getSubmittedOrder();
            const hasSubmittedOrder = store.hasSubmittedOrder();
            const order = hasSubmittedOrder ? submittedOrder : store.order;            
            const issConfig = store.issConfig;
            const applicationUser = store.applicationUser;

            // NOTE: ISS does not support early bird times.            
            const isEarlyBird = false; /*order?.lineItems?.supportingItems?.find(
                (lineItem) => lineItem.partType == partTypeStrings.EARLY_BIRD
            );
            */
            
            // NOTE: No promo codes on ISS at the moment.
            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}`
            );

            const format = (part) => `${part?.partNumber}-${part?.partType ? part.partType : ""}`;
            const mapParts = (arr) => (arr ?? []).map(format);

            const glassParts = mapParts(order?.lineItems?.glassParts);
            const supportingItems = mapParts(order?.lineItems?.supportingItems);
            const vaps = mapParts(order?.lineItems?.vaps);
            const childParts = [].concat(
                ...(order?.lineItems?.glassParts ?? []).map((gp) => mapParts(gp?.childParts))
            );
            const allParts = [...glassParts, ...supportingItems, ...vaps, ...childParts];

            if (applicationUser?.pageData?.quote?.servicePackageSelected) {
                allParts.push(applicationUser.pageData.quote.servicePackageSelected);
            }

            var appointment = `${order?.schedule?.date ?? ""} ${order?.schedule?.startTime ?? ""}`;
            var currentPageName = this.getPageNameByQueryString();
/*
            // add query strings to the page name for debugging.  on the vehicle page, if from an external link, pull it from the stash
            if (currentPageName === "vehicle") {
                if (!window.location.search) {
                    if (store.getters.externalParameterState?.qsStash) {
                        currentPageName += `${store.getters.externalParameterState.qsStash}`;
                    }
                } else {
                    currentPageName += `${window.location.search}`;
                }
            } else {
                if (window.location.search) {
                    currentPageName += `${window.location.search}`;
                }
            }
*/
            var parentAccountNumber = (order?.parentAccountNumber ?? ( issConfig.parentAccountNumber ?? 0)).toString();

            var sessionData = {};
            sessionData.currentPage = currentPageName;
            sessionData.sid = getSessionIdValue();
            sessionData.deviceId = getDeviceIdValue();
            sessionData.issSessionId = applicationUser?.savedSessionId;
            sessionData.skey = getSessionKeyValue().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 = "Insurance";
            sessionData.damageType = order?.damage?.isRepair ? "Repair" : "Replace";
            sessionData.productType = allParts;
            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 = store.isPayInAdvance;
            sessionData.piaType = (store.isPayInAdvance ? order?.payment?.paymentMethod : null);

            sessionData.parentAccountNumber = parentAccountNumber;
            sessionData.billToAccountNumber = issConfig.billToAccountNumber;
            sessionData.settledTenderAmount = order?.payment?.nextGenSettledAmount;
            sessionData.recalRequired = store.hasRecalibrationPart;
            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?.contactInfo?.notesForTechnician ? true : false;
            sessionData.paymentMethod = order?.payment?.paymentMethod;
            sessionData.isTextingOptedIn = order?.contactInfo?.requestTextUpdates ? true : false;
            sessionData.isEarlyBird = isEarlyBird;

            sessionData.insuranceCo = issConfig.clientName;
            sessionData.deductible = store.currentDeductible ?? 0;
            sessionData.isVerified = store.isVerified;
            sessionData.coverageStatus = coverageStatuses.mapToApi(order?.insuranceCoverage.coverageStatus);
            sessionData.coverageSubStatus = coverageType.mapToApi(order?.insuranceCoverage.coverageType);

            sessionData.isNoComp = store.isNoComp;
            sessionData.isItac = store.isITAC;            
            sessionData.subTotalPrice = getSubtotal(order).toString();
            sessionData.totalPrice = getCartTotal(order).toString();
            sessionData.cashPriceSubTotal = getSubtotal(order).toString();

            sessionData.userAgent = navigator.userAgent;

            store.logIssSessionData(sessionData);
        },

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

            const deviceId = getDeviceIdValue(); // cookieNames.DXDEV
            const userId = getUserIdValue(); // cookieNames.ISS_USER_ID
            const sid = getSessionIdValue(); // cookieNames.SESSION_ID
            // const skey = getSessionKeyValue();
            const referrer = applicationConfig.CURRENT_ENVIRONMENT !== 'Localhost' ? document.referrer : null;
            const payload = {
                deviceId,
                referrer,
                sessionId: sid,
                userId,
                userAgent: navigator.userAgent
            };

            const response = await useMainStore().initializeSession(payload);

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

        noSession() {
            return !areAllSessionCookiesSet();
        }
    },
    computed: {
        analyticsPageEvents() {
            return analyticsPageEvents;
        },
        GaCategories() {
            return GaCategories;
        },
        GaActions() {
            return GaActions;
        },
        GaLabels() {
            return GaLabels;
        },
        ValueToLogTypes() {
            return ValueToLogTypes;
        }
    }
};
