// Supporting files
import { createWebHistory, createRouter } from "vue-router";
import { storeActions } from "@/constants/store-actions";
import { storeMutations } from "../constants/store-mutations";
import { sessionStorageKeyConstants } from "@/constants/session-storage.js";
import { lazyLoadComponent } from "@/router/dynamic-routing/component-loader.js";
import { routingTable } from "@/router/router-constants/routing-table.js";
import { globalEvents, globalEventTypes } from "@/constants/events";
import { queryStrings } from "@/constants/query-strings";
import { getQuerystringParameter, buildQuerystringObject } from "@/helpers/querystring-helper";
import { getDeviceIdValue } from "@/helpers/heritage-integration/cookie-helper";
import { showFmgLoadingModal } from "@/helpers/loading-modal-helper";
import { fmgPageValues, funnelStartPageName } from "@/router/router-constants/fmgPage-values";
import { externalParameterStatus } from "@/constants/external-parameters";

// Heritage integration
import { isSavedSessionStillActive } from "@/helpers/heritage-integration/session-helper";
import {
    updateOrCreateFunnelCookie,
    getFunnelCookie,
    updateSessionIdCookie,
    deleteFunnelCookie,
    getAffiliateCookies,
    setupAdvertiserTracking,
} from "@/helpers/heritage-integration/cookie-helper";
import { loadSessionIfPresent, saveSession } from "@/helpers/heritage-integration/order-helper";
import {
    getPageToRouteExistingOrderTo,
    navigateToHeritageFunnel,
    getImplicitNavigation,
} from "@/helpers/heritage-integration/navigation-helper";

import baseMixin from "@/mixins/base-mixin";
import eventBus from "@/helpers/event-bus/event-bus";
import store from "@/store";
import analyticsMixin from "@/mixins/analytics-mixin";
import { experimentTriggers } from "../constants/experiments";
import { applicationConfig } from "../constants/application-config";
import { shouldStripPromoQueryString } from "@/helpers/promotions-helper";
import bailout from "@/layouts/bailout/bailout";
import { nextTick } from "vue";
import { getBoolFromString } from "@/helpers/boolean-helper";

const routes = [
    {
        path: "/bailout",
        name: "bailout",
        component: bailout,
    },
    {
        path: "/",
        name: "root",
        async beforeEnter(to, from, next) {
            // If we have no query string, or we don't have the FmgPage query string.
            try {
                log("------------- router index.js beforeEnter start -----------------");
                log(" --to: ", to);
                log(" --cookie: ", getFunnelCookie());
                log(` --from.redirectedFrom:>${JSON.stringify(from.redirectedFrom)}<`, "");

                await analyticsMixin.methods.validateSession();
                var fromHeritage = getQuerystringParameter(queryStrings.FROM_HERITAGE);
                var offerQuote = getQuerystringParameter(queryStrings.OFFER_QUOTE);
                log(" --offerQuote: ", offerQuote);
                // after session is validated, remove the fromHeritage querystring if it exists so session expiration works
                if (to.query) {
                    delete to.query[queryStrings.FROM_HERITAGE];
                }
                //remove offerquote querystring if it exists
                if (offerQuote) {
                    delete to.query[queryStrings.OFFER_QUOTE];
                }

                if (getFunnelCookie()?.SuppressConceptFunnel) {
                    log(" --go to heritage suppressConceptFunnel: ");
                    await navigateToHeritageFunnel({ shouldSaveSession: false });
                    return next(false);
                }

                // If the saved session has timed out, clear the session, execute 404 logic.
                if (getFunnelCookie() !== null && !isSavedSessionStillActive()) {
                    log(" --save session timeout go to start");

                    const errorPayload = {
                        cause: "expired session",
                        currentPage: from?.query?.fmgPage,
                        nextPage: to?.query?.fmgPage,
                    };

                    await baseMixin.methods.dispatchStoreAction(storeActions.RESET_STATE);
                    deleteFunnelCookie();
                    GoToFunnelStartOn404(next, errorPayload);
                    return;
                }

                const fromReturnUser = from?.name === fmgPageValues.RETURN_USER;
                const fromContentSite = getQuerystringParameter(queryStrings.START_TYPE) === "fmg";
                const toReturnUserPage = to.query?.fmgPage === fmgPageValues.RETURN_USER;
                log(" --fromReturnUser ", fromReturnUser);
                log(" --to.query.fmgPage ", to.query?.fmgPage);

                // Intercept all navigation if a submitted order exists in storage
                if (
                    window.sessionStorage.getItem(sessionStorageKeyConstants.SUBMITTED_STATE) !==
                    null
                ) {
                    if (to.query.fmgPage !== funnelStartPageName) {
                        to.query.fmgPage = fmgPageValues.CONFIRMATION;
                        log(
                            ` --has ${sessionStorageKeyConstants.SUBMITTED_STATE} go to confirmation`
                        );
                    }
                }
                // On entering the funnel "fresh", read cookie information, decide what to do next.
                else if (from.redirectedFrom === undefined || fromReturnUser) {
                    // if entering the funnel from the content site, check and see if there is already a vehicle year in vuex.
                    // if so, send them to return-user page.
                    if (
                        fromContentSite &&
                        !toReturnUserPage &&
                        store.getters.order.vehicle?.year > 0
                    ) {
                        log(" --from content site navigate to return user");
                        var qso = {
                            fmgPage: fmgPageValues.RETURN_USER,
                        };

                        const newQueryString = buildQuerystringObject(qso, true);
                        log(" -- returnUser add querystring: " + JSON.stringify(newQueryString));

                        router.push({
                            path: "/",
                            query: Object.assign({}, newQueryString),
                        });
                        return;
                    }

                    // clear the saveSessionPromise - if it exists in the vuex store but a new instance was created
                    //   the saveSessionPromise will no longer point to a valid promise
                    log(" --clear promise");
                    baseMixin.methods.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);

                    if (!to.query.fmgPage?.startsWith("payment")) {
                        //payment pages used to return from safelitehop so exclude here
                        // Remove the parameter after quote release

                        // for testing end to end locally, see if there is a referralNumber on the querystring
                        // that could have changed in heritage and then stick it in the store and then update the cookie
                        // so load-session runs properly. this can be removed when heritage goes away
                        const referralNumber = getQuerystringParameter(
                            queryStrings.REFERRAL_NUMBER
                        );
                        const parentAccount = getQuerystringParameter(queryStrings.PARENT_ACCOUNT);
                        const correlationId = getQuerystringParameter(queryStrings.CORRELATION_ID);
                        if (referralNumber) {
                            store.commit(storeMutations.UPDATE_REFERRAL_NUMBER, referralNumber);
                            store.commit(storeMutations.UPDATE_PARENT_ACCT_NUMBER, parentAccount);
                            store.commit(
                                storeMutations.UPDATE_REFERRAL_CORRELATION_ID,
                                correlationId
                            );
                            log(" --update cookie");
                            updateOrCreateFunnelCookie();
                        }

                        //Affiliate Cookies
                        const affiliateCookies = getAffiliateCookies();
                        if (affiliateCookies != null && affiliateCookies.length > 0) {
                            store.commit(storeMutations.UPDATE_AFFILIATE_COOKIES, affiliateCookies);
                        }
                        setupAdvertiserTracking();
                        log(" --load session start");
                        const loadSessionResponse = await loadSessionIfPresent(
                            to.query.isInsurance != null
                                ? to.query.isInsurance == "true"
                                    ? true
                                    : false
                                : null,
                            to.query.fmgPage
                        );
                        log(" --load session end");

                        //Update external parameter state but not when returning from heritage
                        if (!to.query.fmgPage?.startsWith("service-location") && !fromReturnUser) {
                            updateExternalParameterState();
                        }

                        //Update CASH tab when return from heritage and have offerQuote param
                        if (offerQuote === "true" && fromHeritage === "true") {
                            store.commit(storeMutations.UPDATE_IS_INSURANCE, false);
                        }

                        // clear part related state because heritage selected a new vehicle
                        if (
                            to.query.fmgPage === fmgPageValues.VEHICLE &&
                            getBoolFromString(getFunnelCookie()?.HasDelayedClaimRegistration) &&
                            !fromReturnUser
                        ) {
                            store.commit(storeMutations.RESET_GLASS_PARTS_STATE);
                        }

                        // if coming from the return user page, clear the destination page so implicit navigation runs
                        log(" --to.query ", JSON.stringify(to.query));
                        if (fromReturnUser && to.query) {
                            log(" --clear to.query");
                            delete to.query[queryStrings.FMG_PAGE];

                            //to.query[queryStrings.FMG_PAGE] = "";
                            log(" --to.query cleared ", JSON.stringify(to.query));
                        }

                        const pageToRedirectTo = await getPageToRouteExistingOrderTo(to);
                        log(" --pageToRedirectTo ", JSON.stringify(pageToRedirectTo));

                        // This logic may determine that the user should be sent to heritage -- if so, do that here.
                        if (pageToRedirectTo === fmgPageValues.HERITAGE) {
                            // prettier-ignore
                            log(" --go to heritage pageToRedirectTo ", JSON.stringify(pageToRedirectTo));
                            await navigateToHeritageFunnel({ shouldSaveSession: false });
                            return next(false);
                        }

                        // Assign our fmgPage so it will load normally like the other pages.
                        to.query.fmgPage = pageToRedirectTo;
                        log(" --assign to: ", JSON.stringify(pageToRedirectTo));
                    }
                }

                // Reroute around pages that should not be available.

                // Exception 1: Integrated Users should not see vehicle or quote pages.
                if (
                    store.getters.payment?.insuranceCoverage?.isVerified ||
                    store.getters.order?.referralNumber?.length === 6
                ) {
                    if (to.query.fmgPage === fmgPageValues.VEHICLE) {
                        to.query.fmgPage = fmgPageValues.VEHICLE_DAMAGE;
                    } else if (
                        to.query.fmgPage === fmgPageValues.QUOTE ||
                        to.query.fmgPage === fmgPageValues.INSURANCE_COMPANY
                    ) {
                        log(" --block quote page for integrated clients - go to heritage");
                        // Push to heritage if going to quote & integrated.
                        await navigateToHeritageFunnel({ shouldSaveSession: false });
                        return next(false);
                    }
                }

                await runExperiments(to.query.fmgPage);

                //Affiliate Cookies
                const affiliateCookies = getAffiliateCookies();
                if (affiliateCookies != null && affiliateCookies.length > 0) {
                    store.commit(storeMutations.UPDATE_AFFILIATE_COOKIES, affiliateCookies);
                }
                setupAdvertiserTracking();
                // Process funnel cookie.
                updateOrCreateFunnelCookie();

                // If we already have our route, go to it.
                if (router.hasRoute(to.query.fmgPage)) {
                    // Since our route is already in scope, we can grab the component from it and call the arePagePrerequisitesValid function.
                    let component = router
                        .getRoutes()
                        .filter((x) => x.name === to.query.fmgPage)[0].components;

                    // If the component hasn't been loaded fully, load it before we check prerequisites.
                    if (component.default.methods === undefined) {
                        component = await component.default();
                    }

                    if (!arePagePrerequisitesValid(component)) {
                        console.log("Page prereq error: " + component.default.name);

                        if (to.query.fmgPage === fmgPageValues.PAYMENT) {
                            await store.getters.applicationUser.saveSessionPromise;
                            window.location = applicationConfig.PIA_CANCEL_URL;
                            return;
                        }

                        const errorPayload = {
                            cause: "invalid page prerequisites for page",
                            currentPage: from?.query?.fmgPage,
                            nextPage: to?.query?.fmgPage,
                        };

                        GoToFunnelStartOn404(next, errorPayload);
                        return;
                    }

                    log(" --has route:", to.query.fmgPage);
                    return next({ name: to.query.fmgPage, query: to.query, params: to.params });
                }

                if (!isExistingFmgPageName(to.query.fmgPage)) {
                    const errorPayload = {
                        cause: "invalid page name",
                        currentPage: from?.query?.fmgPage,
                        nextPage: to?.query?.fmgPage,
                    };

                    GoToFunnelStartOn404(next, errorPayload);
                    return;
                }

                // Get route info for the given url. Names will have a 1:1 relationship with names in the Cms.
                const routeData = GetRouteInfoFromPageName(to.query.fmgPage);
                log("--routeData:", routeData);

                // Add our dynamic route.
                router.addRoute({
                    path: routeData[0].path, // Always the same path, because we control it with query strings.
                    name: routeData[0].name,
                    component: routeData[0].component,
                });

                // Call the next components arePagePrerequisitesValid method before load.
                // If it returns false, use the 404 logic.
                const nextComponent = await router
                    .getRoutes()
                    .filter((x) => x.name === routeData[0].name)[0]
                    .components.default();

                if (!arePagePrerequisitesValid(nextComponent)) {
                    // prettier-ignore
                    console.log("Page Prereqs not valid for next component: " + nextComponent.default.name);

                    const errorPayload = {
                        cause: "invalid page prerequisites for page",
                        currentPage: from?.query?.fmgPage,
                        nextPage: to?.query?.fmgPage,
                    };

                    GoToFunnelStartOn404(next, errorPayload);
                    return;
                }

                log("------------- router index.js beforeEnter end -----------------");

                // Assign current query string parameters, as well as our fmgPage one.
                next({
                    name: routeData[0].name,
                    query: Object.assign(to.query, { fmgPage: routeData[0].name }),
                    params: to.params,
                });
            } catch (error) {
                global.$logger.logError(`Routing ${error.stack}`);

                if (to.query?.fmgPage === funnelStartPageName) {
                    deleteFunnelCookie();
                    await baseMixin.methods.dispatchStoreAction(storeActions.RESET_STATE);
                }

                console.log(new Date() + " Exception in beforeEnter:" + JSON.stringify(error));

                // If we don't have a route, go to our 404 page.
                const errorPayload = {
                    cause: "uncaught error in beforeEnter",
                    currentPage: from?.query?.fmgPage,
                    nextPage: to?.query?.fmgPage,
                    fullError: error,
                    errorStack: error?.stack,
                };

                GoToFunnelStartOn404(next, errorPayload);
                return;
            }
        },
    },
];

const router = createRouter({
    history: createWebHistory("/fmg/"),
    routes,
    //Cause "page" to begin at the top when route chanages.
    scrollBehavior(to, from, savedPosition) {
        // always scroll to top
        return { top: 0 };
    },
});

//---------------------------------------------------------- Router Functions ----------------------------------------------------------

router.beforeEach(async (to, from, next) => {
    log("------------- router index.js beforeEach start -----------------");
    // set lastNavigationPage here to capture state before API calls for analytics.
    // use current page url query string name when to.name is "root" (due to unresolved navigation in beforeEach)
    router.lastNavigationPage = to.name == "root" ? analyticsMixin.methods.getPageName() : to.name;

    const fromQueryPage = from.query?.fmgPage;
    if (fromQueryPage === undefined) {
        showFmgLoadingModal(true);
    }

    const toQueryPage = to.query?.fmgPage;
    const notToPIAReturn = toQueryPage != fmgPageValues.PAYMENT_PIA_RETURN;
    const isInIframe = window !== window.top;

    if (store.getters.externalParameterState?.isExternalParameter) {
        // Check if alert event is on the bus
        const alertEvent = eventBus.readEventFromBus(
            globalEvents.Categories.GLOBAL_ALERT,
            globalEvents.SubCategories.PAGE_NOT_FOUND
        );
        //Uknown alerts most likely were added by a failed api call in global-methods
        const unknownAlertEvent = eventBus.readEventFromBus(
            globalEvents.Categories.GLOBAL_ALERT,
            globalEvents.SubCategories.UNKNOWN_ERROR
        );
        // If alert event is on the bus, then display the alert
        if (alertEvent !== undefined || unknownAlertEvent !== undefined) {
            store.commit(
                storeMutations.UPDATE_IS_EXTERNAL_PARAMETER,
                externalParameterStatus.INACTIVE
            );
        }
    }
    // fromPaymentToConfirmation workaround for navigating from an iframe but
    // isInIframe evaluates to false for some reason when navigating from payment to confirmation
    const fromPaymentToConfirmation =
        fromQueryPage === fmgPageValues.PAYMENT && toQueryPage === fmgPageValues.CONFIRMATION;

    if ((isInIframe && notToPIAReturn) || fromPaymentToConfirmation) {
        const newUrl = `${window.top.location.origin}${to.href}`;
        window.top.location.href = newUrl;
        next(false);

        // Refresh page if navigating to self to prevent locking.
        // For now only carved out for vehicle; all modals are opened through anchor tags at the moment,
        // which also self navigate, but relied on the page remaining the same on self-navigation.
    } else if (toQueryPage === fromQueryPage && toQueryPage === getRedirectedStartPage()) {
        router.go(0);
        next(false);
    } else {
        next();
    }
    log("------------- router index.js beforeEach end -----------------");
});

router.afterEach(async (to, from) => {
    // Update lastPageVisited in the store
    store.commit(storeMutations.UPDATE_LAST_PAGE_VISITED, to.name);

    // If saving on navigation is requested, check for saved SessionId or EmailAddress to determine if saving is appropriate
    if (getBoolFromString(window.history.state.isSavingNavigation)) {
        if (
            store.getters.applicationUser.savedSessionId ||
            store.getters.order.customer?.emailAddress
        ) {
            await saveSession({ pageNameToLog: to.query.fmgPage });
        }
    }

    // Push page view to GA
    analyticsMixin.methods.pushPageViewToGA();

    // Push experiments to Data Layer
    analyticsMixin.methods.pushExperimentsToDataLayer();

    // Push current order status to Data Layer
    analyticsMixin.methods.pushOrderToDataLayer();

    if (to.query.fmgPage == fmgPageValues.CONFIRMATION) {
        //Push Ecommerce Cart to Data Layer
        analyticsMixin.methods.pushECommerceCartToDataLayer();

        //Push Product Array to Data Layer
        analyticsMixin.methods.pushProductArrayToDataLayer();

        //Push Commission Junction Gtm Data To Data Layer
        analyticsMixin.methods.pushCommissionJunctionGtmDataToDataLayer();
    }
});

router.navigateWithoutSaving = (
    scenario,
    currentRoute,
    optionalQuery = {},
    optionalParams = {},
    optionalPageData = {}
) => {
    navigate(scenario, currentRoute, false, optionalQuery, optionalParams, optionalPageData);
};

router.navigateWithSaving = (
    scenario,
    currentRoute,
    optionalQuery = {},
    optionalParams = {},
    optionalPageData = {}
) => {
    navigate(scenario, currentRoute, true, optionalQuery, optionalParams, optionalPageData);
};

router.navigateToExternalUrl = (url, optionalQuery = {}) => {
    log("------------- router navigateToExternalUrl -----------------");
    log("url:", url);
    navigateToUrl(url, optionalQuery);
};

router.navigateError = (errorPayload = null) => {
    DisplayPageError(errorPayload);
};

//Use this navigation when you need to call next() explicitly. beforeRouteEnter is a good example.
router.overrideNavigation = (
    scenario,
    currentRoute,
    next,
    isSavingNavigation,
    optionalQuery = {},
    optionalParams = {},
    optionalPageData
) => {
    log("------------- router overrideNavigation -----------------");
    log("scenario:", scenario);
    log("currentRoute:", currentRoute);
    log("isSavingNavigation:", isSavingNavigation);
    log("optionalQuery:", optionalQuery);
    log("optionalParams:", optionalParams);
    log("optionalPageData:", optionalPageData);
    navigate(
        scenario,
        currentRoute,
        isSavingNavigation,
        optionalQuery,
        optionalParams,
        optionalPageData
    );
    next();
};

router.getNextPage = () => nextPageName;

// PRIVATE VARIABLES

var nextPageName;

// PRIVATE FUNCTIONS

// Navigate to the next route, depending on the scenario.
async function navigate(
    scenario,
    currentRoute,
    isSavingNavigation,
    optionalQuery = {},
    optionalParams = {},
    optionalPageData = {}
) {
    if (!scenario) {
        console.error("No scenario provided. Please review the routing table.");
        return;
    }

    // Match our maps up and navigate if we have a destination.
    const matchingScenarioMap = getNavigationMap(scenario, currentRoute);
    const destinationFmgPageValue = matchingScenarioMap.destinationFmgPageValue;

    if (destinationFmgPageValue !== undefined) {
        // We're always pushing the same path, just changing query strings. Make sure our optional query strings get combined with our fmgPage one.

        nextPageName = destinationFmgPageValue;

        // Update page data to the store for next page if provided. Otherwise, keep existing page data or set to empty object
        const existingPageDataForPage = store.getters.pageData(destinationFmgPageValue);
        baseMixin.methods.savePageDataToStore(
            destinationFmgPageValue,
            Object.keys(optionalPageData).length > 0
                ? optionalPageData
                : (existingPageDataForPage ?? {})
        );

        optionalParams.isSavingNavigation = isSavingNavigation;

        // add querystring params to the route. if they are already in the store then no need to add them
        var queryStringsObject = {
            fmgPage: destinationFmgPageValue,
        };

        const hasZip = getQuerystringParameter(queryStrings.ZIP_CODE);
        const zip = getQuerystringParameter(queryStrings.ZIP_CODE);
        const promo = getQuerystringParameter(queryStrings.PROMO);
        const pageError = getQuerystringParameter(queryStrings.PAGE_ERROR);
        const logQs = getQuerystringParameter(queryStrings.LOG);
        baseMixin.methods.dispatchStoreAction(storeActions.SAVE_LOGGING_OPTION, logQs, false);

        log("------------- router index.js navigate start -----------------");
        log(" --scenario: ", scenario);
        log(" --isSavingNavigation: ", isSavingNavigation);
        log(" --optionalQuery: ", optionalQuery);
        log(" --optionalParams: ", optionalParams);
        log(" --optionalPageData: ", optionalPageData);
        log(" --nextPageName: ", nextPageName);

        if (
            hasZip &&
            (store.getters.order.serviceLocation.zipCode === undefined ||
                store.getters.order.serviceLocation.zipCode == null) &&
            (store.getters.order.vehicle.registration.zipCode === undefined ||
                store.getters.order.vehicle.registration.zipCode == null)
        ) {
            queryStringsObject[queryStrings.ZIP_CODE] = zip;
        }

        if (promo && !shouldStripPromoQueryString(currentRoute.query.fmgPage)) {
            queryStringsObject[queryStrings.PROMO] = promo;
        }

        if (pageError) {
            queryStringsObject[queryStrings.PAGE_ERROR] = pageError;
        }

        if (logQs) {
            queryStringsObject[queryStrings.LOG] = logQs;
        }

        log(" querystrings: ", queryStringsObject);
        log("------------- router index.js navigate end -----------------");

        router.push({
            name: "root",
            query: Object.assign(optionalQuery, queryStringsObject),
            state: optionalParams,
        });
    } else if (matchingScenarioMap.destinationUrl !== undefined) {
        navigateToUrl(matchingScenarioMap.destinationUrl, optionalQuery);
    }
}

// Get navigation map depending on the scenario and the current 'page' you're on.
function getNavigationMap(scenario, currentRoute) {
    const fmgPageValue = currentRoute.query.fmgPage;
    log("------------- router index.js getNavigationMap start -----------------");
    log("fmgPage: " + fmgPageValue + " scenario: " + scenario, "");
    log("------------- router index.js getNavigationMap end -----------------");
    const matchedQueryValue = routingTable(store)
        .filter(
            (item) =>
                item.fmgPageValue === fmgPageValue &&
                item.maps.filter((map) => map.scenario === scenario).length > 0
        )
        .map((m) => m.maps.filter((map) => map.scenario === scenario))[0]
        .filter((x) => x.filter === true || x.filter === undefined);

    return matchedQueryValue[0];
}

function log(message, data) {
    const log = getQuerystringParameter(queryStrings.LOG);
    baseMixin.methods.dispatchStoreAction(storeActions.SAVE_LOGGING_OPTION, log, false);

    data = data ?? "";
    const outData = typeof data === "object" ? JSON.stringify(data) : data;

    if (log === "true" || store.getters.applicationUser.loggingOption) {
        console.log(new Date() + message + outData);
    }
}

//---------------------------------------------------------- Private Functions ----------------------------------------------------------

// Navigate to an external url.
function navigateToUrl(url, optionalQuery = {}) {
    // possibly show some loading screen in the future here.
    var externalUrl = new URL(url);

    for (const queryKey in optionalQuery) {
        externalUrl.searchParams.append(queryKey, optionalQuery[queryKey]);
    }

    window.location.assign(externalUrl);
}

// Get route information by page name.
// This will no longer reach out to the Cms. There is a 1:1 relationship between page names and route names and layouts.
function GetRouteInfoFromPageName(pageName) {
    // check if pagename is a valid route/component
    if (!isExistingFmgPageName(pageName)) {
        return [];
    }

    const routeData = [
        {
            path: "/",
            name: pageName,
            component: lazyLoadComponent(pageName),
        },
    ];

    return routeData;
}

// Go to our start page on a 404.
function GoToFunnelStartOn404(next, errorPayload = null) {
    if (errorPayload !== null) {
        errorPayload.type = "GoToFunnelStartOn404";
        analyticsMixin.methods.pushPageErrorToDataLayer(errorPayload);

        console.log(
            "%cGoToFunnelStartOn404()... errorPayload",
            "color: white; background-color: blue; padding: 5px;",
            errorPayload
        );
    }

    // Put item on the bus
    eventBus.addEventToBus(
        globalEvents.Categories.GLOBAL_ALERT,
        globalEvents.SubCategories.PAGE_NOT_FOUND,
        {
            isDismissible: true,
            messageCopy: "You can get a quote by starting on this page.",
            messageHeadline: "We're sorry, something went wrong.",
            type: globalEventTypes.Danger,
        }
    );

    next({
        path: "/",
        query: { fmgPage: funnelStartPageName },
    });
}

async function DisplayPageError(errorPayload = null) {
    console.log("%c running DisplayPageError()... ", "font-size: 20px; color: purple;");

    if (errorPayload !== null) {
        errorPayload.type = "DisplayPageError";
        analyticsMixin.methods.pushPageErrorToDataLayer(errorPayload);
    } else {
        // very cautiously to avoid additional errors:
        var currentPage = "";
        try {
            currentPage = getQuerystringParameter(queryStrings.FMG_PAGE);
        } catch (e) {
            // pass
        }
        errorPayload = {
            type: "DisplayPageError",
            cause: "Unknown page error",
            currentPage: currentPage,
        };
        analyticsMixin.methods.pushPageErrorToDataLayer(errorPayload);
    }

    // Put item on the bus
    eventBus.addEventToBus(
        globalEvents.Categories.GLOBAL_ALERT,
        globalEvents.SubCategories.UNKNOWN_ERROR,
        {
            isDismissible: true,
            messageCopy: "",
            messageHeadline: "We're sorry, something went wrong.",
            type: globalEventTypes.Danger,
        }
    );
    if (
        store.getters.externalParameterState?.isExternalParameter == externalParameterStatus.ACTIVE
    ) {
        store.commit(storeMutations.UPDATE_IS_EXTERNAL_PARAMETER, externalParameterStatus.INACTIVE);
    }
    baseMixin.methods.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
    const pageError = getQuerystringParameter(queryStrings.PAGE_ERROR);

    // we use the pageError querystring as a counter to how many times a user has experienced an error and been routed here.
    // once they receive more than 1 pageerrors, we'll reset their state to hopefully correct any issues they may be having.
    var navPage = fmgPageValues.VEHICLE;
    if (store.getters.payment?.insuranceCoverage?.isVerified) {
        navPage = fmgPageValues.VEHICLE_DAMAGE;
    }

    if (pageError) {
        var errorCount = Number(pageError);
        if (errorCount > 1) {
            deleteFunnelCookie();
            await baseMixin.methods.dispatchStoreAction(storeActions.RESET_STATE);

            router.push({
                path: "/",
                query: { fmgPage: navPage },
            });
        } else {
            errorCount++;
            router.push({
                path: "/",
                query: { fmgPage: navPage, pageError: errorCount },
            });
        }
    } else {
        router.push({
            path: "/",
            query: { fmgPage: navPage, pageError: "1" },
        });
    }
}

function isExistingFmgPageName(pageName) {
    const names = Object.values(fmgPageValues);

    return names.some((name) => name === pageName);
}

// Checks arePagePrerequisitesValid on the component passed in.
function arePagePrerequisitesValid(component) {
    return component.default.methods.arePagePrerequisitesValid();
}

// Run SiteEntry and PageEntry triggers for experiments
async function runExperiments(nextPage) {
    if (!store.getters.applicationUser.triggeredSiteEntry) {
        await baseMixin.methods.dispatchStoreActionWithLogging(
            storeActions.RUN_EXPERIMENTS_FOR_TRIGGER,
            {
                deviceId: getDeviceIdValue(),
                triggerEvent: experimentTriggers.SITE_ENTRY,
                triggerValue: applicationConfig.SITE_ENTRY_TRIGGER_VALUE,
            },
            nextPage
        );
    }

    await baseMixin.methods.dispatchStoreActionWithLogging(
        storeActions.RUN_EXPERIMENTS_FOR_TRIGGER,
        {
            deviceId: getDeviceIdValue(),
            triggerEvent: experimentTriggers.PAGE_ENTRY,
            triggerValue: nextPage,
        },
        nextPage
    );
}

function getRedirectedStartPage() {
    if (store.getters.payment?.insuranceCoverage?.isVerified) {
        return fmgPageValues.VEHICLE_DAMAGE;
    } else {
        return funnelStartPageName;
    }
}

function updateExternalParameterState() {
    const externalParameterYear = getQuerystringParameter(queryStrings.VEHICLE_YEAR);
    const externalParameterMake = getQuerystringParameter(queryStrings.VEHICLE_MAKE);
    const externalParameterModel = getQuerystringParameter(queryStrings.VEHICLE_MODEL);
    const externalParameterStyle = getQuerystringParameter(queryStrings.VEHICLE_STYLE);
    const externalParameterDamage = getQuerystringParameter(queryStrings.VEHICLE_DAMAGE);
    const externalParameterZipCode = getQuerystringParameter(queryStrings.SERVICE_ZIP);
    const externalParameterEmail = getQuerystringParameter(queryStrings.EMAIL);
    const externalParameterIsInsurance = getQuerystringParameter(queryStrings.IS_INSURANCE);
    const externalParameterVinSelection = getQuerystringParameter(queryStrings.VIN_SELECTION);
    const externalParameterServicePackage = getQuerystringParameter(queryStrings.SERVICE_PACKAGE);
    const externalParameterNumberOfChips = getQuerystringParameter(queryStrings.NUMBER_OF_CHIPS);
    const externalParameterSource = getQuerystringParameter(queryStrings.EXPERIMENTS);
    const externalParameterPhoneNumber = getQuerystringParameter(queryStrings.PHONE_NUMBER);
    if (
        externalParameterYear &&
        externalParameterMake &&
        externalParameterModel &&
        externalParameterStyle
    ) {
        resetStoreForExternalParameter();
        store.commit(storeMutations.UPDATE_IS_EXTERNAL_PARAMETER, externalParameterStatus.ACTIVE);
        store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_YEAR, externalParameterYear);
        store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_MAKE, externalParameterMake);
        store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_MODEL, externalParameterModel);
        store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_STYLE, externalParameterStyle);
    }
    if (
        externalParameterDamage &&
        (externalParameterDamage.toUpperCase() != "WINDSHIELDREPAIR" ||
            externalParameterNumberOfChips?.length > 0)
    ) {
        store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_DAMAGE_TYPE, externalParameterDamage);
        if (externalParameterDamage.toUpperCase() == "WINDSHIELDREPLACE") {
            store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_IS_REPAIR, false);
            store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_NUMBER_OF_CHIPS, null);
        } else if (externalParameterDamage.toUpperCase() == "WINDSHIELDREPAIR") {
            store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_IS_REPAIR, true);
            store.commit(
                storeMutations.UPDATE_EXTERNAL_PARAMETER_NUMBER_OF_CHIPS,
                externalParameterNumberOfChips
            );
        }
    }
    if (externalParameterZipCode) {
        store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_ZIP_CODE, externalParameterZipCode);
    }
    if (externalParameterEmail) {
        store.commit(
            storeMutations.UPDATE_EXTERNAL_PARAMETER_EMAIL_ADDRESS,
            externalParameterEmail
        );
    }
    if (externalParameterIsInsurance?.toUpperCase() == "TRUE") {
        store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_IS_INSURANCE, true);
        store.commit(
            storeMutations.UPDATE_EXTERNAL_PARAMETER_SERVICE_PACKAGE,
            externalParameterServicePackage?.toLowerCase()
        );
    }
    if (externalParameterDamage?.toUpperCase() != "WINDSHIELDREPAIR") {
        store.commit(
            storeMutations.UPDATE_EXTERNAL_PARAMETER_VIN_SELECTION,
            externalParameterVinSelection
        );
    }
    if (externalParameterSource) {
        store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_SOURCE, externalParameterSource);
    }
    if (externalParameterPhoneNumber) {
        store.commit(
            storeMutations.UPDATE_EXTERNAL_PARAMETER_PHONE_NUMBER,
            externalParameterPhoneNumber
        );
    }
}

// if there is an existing external parameter state then they have already been through from an external source(LeadGen) and
// are returning.  clear out prior related things that need to be selected again like parts and damage type.
function resetStoreForExternalParameter() {
    if (
        store.getters.externalParameterState?.isExternalParameter ==
        externalParameterStatus.INACTIVE
    ) {
        store.dispatch(storeActions.RESET_VEHICLE_STATE_AND_DEPENDENCIES);
        store.dispatch(storeActions.SAVE_SERVICE_ZIP_CODE_INFO, {
            state: null,
            zipCode: null,
            zipCodeCtu: null,
        });
        store.dispatch(storeActions.SAVE_EMAIL, null);
        store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
    }
}

export default router;
