import axios from "axios";
import analyticsMixIn from "@/mixins/analytics-mixin.js";
import baseMixin from "@/mixins/base-mixin.js";
import router from "@/router";
import store from "@/store";

import { applicationConfig } from "@/constants/application-config.js";
import { GaCategories, GaActions, GaLabels } from "@/constants/analytics";
import { getSessionKeyValue } from "@/helpers/heritage-integration/cookie-helper";
import { headerKeys } from "@/constants/header-keys";
import axiosResponseInterceptorMessages from "@/constants/axios-response-interceptor-messages.js";

// Add a response interceptor for global axios error handing.
axios.interceptors.response.use(
    (response) => response,
    (error) => {
        let rejectionError = "";
        if (typeof error.response === "undefined") {
            // The request was not made, could be a bad url, bad connection, or a CORS error.
            rejectionError = {
                response: error,
                message: axiosResponseInterceptorMessages.NETWORK_ERROR,
            };
        } else if (error.response) {
            // The request was made and the server responded with a status code
            // that falls out of the range of 2xx
            rejectionError = {
                response: error.response,
                message: axiosResponseInterceptorMessages.STATUS_CODE_ERROR,
            };
        } else if (error.request) {
            // The request was made but no response was received
            // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
            // http.ClientRequest in node.js
            rejectionError = {
                response: error.request,
                message: axiosResponseInterceptorMessages.NO_RESPONSE_ERROR,
            };
        } else {
            // Something happened in setting up the request that triggered an Error
            rejectionError = {
                response: error.message,
                message: axiosResponseInterceptorMessages.GENERIC_ERROR,
            };
        }

        return Promise.reject(rejectionError);
    }
);

export default {
    callHttpClient({
        method,
        endpoint,
        payload,
        logApiCall = false,
        pageNameToLog = null,
        additionalSuccessEventDataHandler,
    }) {
        return new Promise((resolve, reject) => {
            const cfDistroUrl = applicationConfig.CONSUMER_CF_DISTRO;
            const submittedOrder = baseMixin.methods.getSubmittedOrder();
            const hasSubmittedOrder = baseMixin.methods.hasSubmittedOrder();
            const order = hasSubmittedOrder ? submittedOrder : store.getters.order;
            const payloadAndAnalyticsData = Object.assign({}, payload, { AppName: "FixMyGlass" });
            const headers = {
                [headerKeys.EXPERIMENT]: JSON.stringify(store.getters.experimentSettings),
                [headerKeys.APPLICATION_NAME]: applicationConfig.APPLICATION_NAME,
                [headerKeys.SESSION_SEQUENCE_NUMBER]: getSessionKeyValue(),
                [headerKeys.REFERRAL_SEQUENCE_NUMBER]: order?.referralSequenceNumber,
                [headerKeys.TRANSACTION_ID]: crypto.randomUUID(),
                [headerKeys.EON]: order?.eon,
                [headerKeys.LOG_ENABLED]: store.getters.applicationUser?.loggingOption ?? false,
            };

            axios({
                method: method,
                url: cfDistroUrl + endpoint,
                data: payloadAndAnalyticsData,
                crossDomain: true,
                responseType: {},
                headers: headers,
            }).then(
                (response) => {
                    if (logApiCall) {
                        let additionalEventData = "";
                        if (additionalSuccessEventDataHandler) {
                            additionalEventData = "_" + additionalSuccessEventDataHandler(response);
                        }
                        const endpointWithoutParams =
                            analyticsMixIn.methods.removeParamsFromEndpoint(endpoint);
                        analyticsMixIn.methods.pushEventToGA(
                            GaCategories.API_RESPONSE,
                            `${pageNameToLog}_${endpointWithoutParams}`,
                            `${GaLabels.SUCCESS}${additionalEventData}`,
                            true
                        );
                    }

                    return resolve(response);
                },
                (error) => {
                    if (logApiCall) {
                        analyticsMixIn.methods.pushEventToGA(
                            GaCategories.API_RESPONSE,
                            GaActions.RESULT,
                            `${GaLabels.ERROR}_${endpoint}`,
                            true
                        );
                    }

                    if (error.response.status && error.response.status != "404") {
                        // Do not route to error logic when no wipers found or no promo found (404s)
                        const errorPayload = {
                            cause: `Response error ${error.response.status}`,
                            currentPage: pageNameToLog,
                            endpoint: endpoint,
                        };

                        router.navigateError(errorPayload);

                        // do not log 404 errors from services because we return NotFound
                        // when a service doesn't return an object
                        global.$logger.logError(
                            `${method}: ${endpoint}: ${error.message}`,
                            error.response
                        );
                    }

                    return reject(error.response);
                }
            );
        });
    },

    /* istanbul ignore next */
    callMockHttpClient({ method, endpoint, payload }) {
        // For Mock use only!
        return new Promise((resolve, reject) => {
            axios({
                method: method,
                url: endpoint,
                crossDomain: true,
                headers: {
                    "Content-Type": "application/x-www-form-urlencoded",
                },
                responseType: {},
                data: payload,
            }).then(
                (response) => {
                    // simulate a delayed response
                    setTimeout(() => {
                        resolve(response);
                    }, 2000);
                },
                (error) => {
                    return reject(error.response);
                }
            );
        });
    },
};
