/* eslint-disable no-use-before-define */
/* eslint-disable max-len */
import { defineStore } from 'pinia';
import applicationConfig from '@/constants/application-config';
import bailoutCode from '@/constants/bailoutCode';
import bailoutMessage from '@/constants/bailoutMessage';
import coverageStatuses from '@/constants/coverage-statuses';
import coverageType from '@/constants/coverage-type';
import damageLocationsSelected from '@/constants/damage-locations-selected';
import endpoints from '@/constants/endpoints';
import { experimentSettings, experimentTriggers, experimentUniverses } from '@/constants/experiments';
import partNumberStrings from '@/constants/part-number-strings';
import partTypeStrings from '@/constants/part-type-strings';
import { paymentMethods } from '@/constants/payment-method-constants';
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
import webStorageConstants from '@/constants/web-storage-constants';
// eslint-disable-next-line import/no-cycle
import globalMethods from '@/global-methods';
// eslint-disable-next-line import/no-cycle
import { getSessionKeyValue, getUserIdValue, deleteISSCookie, getDeviceIdValue } from '@/helpers/cookie-helper';
import { convertDateStringToDate, getDateDifferenceInDays, militaryToTwelveHourTime } from '@/helpers/date-helper';
import { getExperimentSettingValue, getFeatureTogglesPayloadObject } from '@/helpers/experiment-helper';
import { findLineItemIndex, getLineItemsFlattened } from '@/helpers/line-items-helper';
import {
    deductibleForSelectedVehicle, endorsementsForSelectedVehicle,
    noCoverageForSelectedVehicle,
    repairWaivedForSelectedVehicle
} from '@/helpers/policy-vehicle-helper';
import {
    buildURLSearchParams,
    getPartNumbersListForQueryString,
    getTaxLineItemQueryString
} from '@/helpers/querystring-helper';
import { getTopLevelGlassPartsWithRecal } from '@/helpers/recal-helper';
// eslint-disable-next-line import/no-cycle
import { getDateForSavedSessionTimeout } from '@/helpers/session-helper';
import issPageValues from '@/router/router-constants/issPage-values';

const storeId = 'main';

function getDisplayTextForDurationLength(durationMinimum, durationMaximum) {
    const isLongAppointment = durationMaximum >= 120;
    const isDurationRange = durationMinimum !== durationMaximum;

    const adjustedMinimum = isLongAppointment ? durationMinimum / 60 : durationMinimum;
    const adjustedMaximum = isLongAppointment ? durationMaximum / 60 : durationMaximum;

    const durationText = isDurationRange
        ? `${adjustedMinimum} - ${adjustedMaximum}`
        : adjustedMinimum;

    const unitText = isLongAppointment ? 'hours' : 'minutes';

    return `${durationText} ${unitText}`;
}

function getTimeSlotsAdditionalEventData(
    provisionalTriggers,
    zipCode,
    firstAvailableAppointmentDateString,
    shopAppointmentType
) {
    let numberOfDays = null;
    if (firstAvailableAppointmentDateString) numberOfDays = getDateDifferenceInDays(new Date(), firstAvailableAppointmentDateString);

    if (shopAppointmentType) return `FirstAvailableAppointment:${numberOfDays},Zip:${zipCode},ShopAppointmentType:${shopAppointmentType},ProvisionalTriggers:${provisionalTriggers.join(',')}`;
    return `FirstAvailableAppointment:${numberOfDays},Zip:${zipCode},ProvisionalTriggers:${provisionalTriggers.join(',')}`;
}

export const getDefaultState = () => ({
    order: {
        vehicle: {
            policyVehicleId: null,
            year: null,
            make: null,
            model: null,
            style: null,
            carId: null,
            category: null,
            vin: null,
            imageUrl: null,
            imageVifNumber: null,
            imageColor: null,
            registration: { // TODO only licensePlate saved in save session
                licensePlate: null,
                address: null,
                city: null,
                state: null,
                zipCode: null,
                firstName: null,
                lastName: null
            },
            isBigTruck: null,
            canSafeliteService: null
        },
        damage: {
            isRepair: null,
            numberOfChips: null,
            glassToReplace: null,
            partQuestionAnswers: null,
            moldingQuestionAnswers: null,
            capabilityQuestionAnswers: null
        },
        policy: {
            policyNumber: null,
            policyZipCode: null,
            dateOfLoss: null,
            damageCause: null,
            damageState: null,
            damageCity: null,
            isDamageGlassOnly: null,
            deductible: {
                repair: null, // numerical value; how much customer owes on deductible in repair case
                replace: null // numerical value; how much customer owes on deductible in replace case,
            },
            vehicles: [],
            endorsements: [],
            endorsementQuestionAnswers: [],
            status: null,
            policyData: null
        },
        customer: {
            address: {
                streetAddress: null,
                streetAddress2: null,
                city: null,
                state: null,
                zipCode: null
            },
            firstName: null,
            lastName: null,
            emailAddress: null
        },
        serviceLocation: {
            address: null,
            address2: null,
            city: null,
            state: null,
            zipCode: null,
            zipCodeCtu: null,
            defaultProviderNumber: null,
            appointmentType: null,
            isVehicleProtected: null,
            IsSafeliteProvider: null,
            searchFilter: null,
            provider: {
                providerNumber: null,
                address: {
                    streetAddress: null,
                    city: null,
                    state: null,
                    zipCode: null,
                    zipCodeCtu: null
                },
                companyName: null,
                phoneNumber: null
            }
        },
        lineItems: {
            glassParts: null,
            otherParts: null,
            supportingItems: null,
            feeItems: [],
            vaps: null,
            serverData: null
        },
        insuranceCoverage: {
            coverageStatus: coverageStatuses.PENDING,
            coverageType: coverageType.NONE,
            isItacOptimized: false,
            claimNumber: null
        },
        payment: {
            parentAccountNumber: 0,
            nextGenSettledAmount: 0,
            paymentMethod: null,
            paypalToken: null,
            creditCardToken: {
                subscriptionId: null,
                expMonth: null,
                expYear: null,
                cardType: null,
                billToPostalCode: null,
                billToFirstName: null,
                billToLastName: null,
                referenceNumber: null,
                authCode: null,
                transactionId: null,
                transReferenceNumber: null,
                lastFour: null
            }
        },
        contactInfo: {
            firstName: null,
            lastName: null,
            emailAddress: null,
            homePhone: null,
            alternativePhone: null,
            servicePhone: null,
            extension: null,
            requestTextUpdates: false,
            notesForTechnician: ''
        },
        schedule: {
            date: null,
            startTime: null,
            endTime: null,
            routeCode: null,
            jobMaxMinutes: null,
            jobMinMinutes: null
        },
        parentAccountNumber: null,
        referralNumber: null,
        referralDate: null,
        referralCorrelationId: '00000000-0000-0000-0000-000000000000',
        referralSequenceNumber: null,
        eon: null,
        workOrderId: null,
        workOrderNumber: null,
        settledTenderAmount: null,
        lockToken: null,
        customerPortalLoginToken: null,
        originalDeductible: {
            repair: null,
            replace: null
        },
        currentDeductible: {
            repair: null,
            replace: null
        },
        totalTaxAmount: null,
        waiverReasons: null,
        carrierPhoneNumber: null,
        loadedFromCookie: false,
        loadedFromDupeCheck: null,
        loadedSessionClearedPreviousData: null,
        availableVaps: null,
        visitedDuplicateCheckPage: false
    },
    applicationUser: {
        experiments: [],
        eventBus: [], // TODO not in save session
        pageData: {},
        savedSessionTimeout: getDateForSavedSessionTimeout(),
        saveSessionPromise: null,
        savedSessionId: '00000000-0000-0000-0000-000000000000',
        crmCustomerId: null,
        lastPageVisited: null,
        triggeredSiteEntry: false, // TODO not in save session
        duplicateOrders: [],
        hasSentSaveQuoteEmail: null,
        coverageLookupAttempts: 0
    },
    issConfig: {
        clientName: 'Generic Insurance', // this is the default and will be overriden by the client's name
        clientFullName: 'Generic Insurance', // this is the default and will be overriden by the client's name or client's full name.
        clientDisplayName: 'Generic Insurance', // this is the default and will be overridden by the client's name or client display name.
        clientHeader: {},
        styleSheet: '', // Stylesheet used by the client.
        parentAccountNumber: 0, // Parent account number used by the client.
        billToAccountNumber: null,
        isCoverageEnabled: false, // Indicates if we should be calling coverage on this flow.
        isClaimRegistrationRequired: false, // Indicates if the claim registration call needs to be made for a client to complete coverage verification.
        isAuthenticated: false, // Indicates if user is authenticated or not.
        enableContinueFromCookie: false, // Indicates if the continue from cookie modal should appear.
        enableTPAFlow: false, // Indicates if the TPA flow is supported for this client.
        successReturnURL: null, // Client URL to return the user to upon a successfull flow completetion (order submission).
        failureReturnURL: null, // Client URL to return the user to when they encounter an error or bailout and are unable to complete the flow.
        disabledFields: { // Fields that are disabled and read only if sent over from a client.
            policyNumber: null,
            policyZipCode: null,
            dateOfLoss: null
        },
        siteType: null,
        enableNoCompQuote: false
    }
});

export const state = getDefaultState();

export const useMainStore = defineStore({
    id: storeId,
    state: () => state,
    getters: {
        billToAccountNumber: (storeState) => storeState.issConfig.billToAccountNumber,
        hasRecalibrationPart: (storeState) => getHasRecalibrationPart(storeState),
        vehicle: (storeState) => storeState.order.vehicle,
        damage: (storeState) => storeState.order.damage,
        lineItems: (state) => state.order.lineItems,
        payment: (state) => state.order.payment,
        policy: (state) => state.order.policy,
        serviceLocation: (state) => state.order.serviceLocation,
        hasExactlyOneChip: () => state.order.damage.numberOfChips === 1,
        isPolicyVehicle: () => state.order.vehicle.policyVehicleId != null,
        hasWindshieldReplacement: (s) => {
            const { damage, lineItems } = s.order;
            return !damage.isRepair
                && (lineItems.glassParts?.some((gp) => gp.partType === partTypeStrings.WINDSHIELD) ?? false);
        },
        hasAnyNonWindshieldGlassParts: (s) => {
            const { damage } = s.order;
            const nonWindshieldItems = damage.glassToReplace?.filter((glass) => glass.glassLocation !== damageLocationsSelected.WINDSHIELD);
            return !!nonWindshieldItems?.length;
        },
        isMobileAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE
            || state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP,
        isDropOffAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.DROP_OFF,
        isInShopAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.IN_SHOP,
        isClaimRegistrationRequired: (state) => state.issConfig.isClaimRegistrationRequired,
        isClaimAlreadyRegistered: (state) => state.order.insuranceCoverage.claimNumber !== null,
        isBailout: (state) => state.applicationUser.pageData[issPageValues.BAILOUT_PAGE] != null,
        bailoutCode: (state) => state.applicationUser.pageData[issPageValues.BAILOUT_PAGE]?.bailoutCode,
        isPolicyLookupSuccessful: (s) => s.order.insuranceCoverage.coverageType !== coverageType.NONE,
        isNoComp: (s) => s.order.insuranceCoverage.coverageType === coverageType.NO_COMP,
        isNoCompQuoteEnabled: (s) => s.issConfig.enableNoCompQuote,
        isITAC: (state) => state.order.insuranceCoverage.coverageType === coverageType.ITAC,
        isDeductible: (state) => state.order.insuranceCoverage.coverageType === coverageType.Deductible,
        isUnverified: (s) => s.order.insuranceCoverage.coverageStatus !== coverageStatuses.VERIFIED,
        isVerified: (state) => state.order.insuranceCoverage.coverageStatus === coverageStatuses.VERIFIED,
        isPendingClaimRegistration: (state) => state.order.insuranceCoverage.coverageStatus === coverageStatuses.PENDING,
        isPayInAdvance: (state) => state.order.payment.paymentMethod != null && state.order.payment.paymentMethod !== paymentMethods.PAY_AT_TIME_OF_SERVICE,
        providerNumber: (state) => state.order.serviceLocation.provider.providerNumber || state.order.serviceLocation.defaultProviderNumber,
        hasOemEndorsement: (state) => state.order.policy.endorsements?.indexOf('OEM Approved') !== -1 ?? false,
        eventBusItem: (state) => (eventCategory, eventSubCategory) => {
            const matchedEvent = state.applicationUser.eventBus.find(({ category, subCategory }) => category === eventCategory && subCategory === eventSubCategory);
            return matchedEvent?.eventValue;
        },
        eventBus: (state) => state.applicationUser.eventBus,
        applicationUserObj: (state) => state.applicationUser,
        pageData: (state) => (page) => (page in state.applicationUser.pageData
            ? state.applicationUser.pageData[page]
            : undefined),
        customerData: (state) => {
            if (state.order.vehicle.registration.address) {
                const { registration } = state.order.vehicle;
                return {
                    addressQuestions: {
                        streetAddress: registration.address,
                        city: registration.city,
                        state: registration.state,
                        zipCode: registration.zipCode
                    },
                    firstName: registration.firstName,
                    lastName: registration.lastName
                };
            }

            const { address } = state.order.customer;
            return {
                addressQuestions: {
                    streetAddress: address.streetAddress,
                    city: address.city,
                    state: address.state,
                    zipCode: address.zipCode
                },
                firstName: state.order.customer.firstName,
                lastName: state.order.customer.lastName
            };
        },
        contactInfo: (s) => ({
            firstName: s.order.contactInfo.firstName ?? s.order.customer.firstName,
            lastName: s.order.contactInfo.lastName ?? s.order.customer.lastName,
            emailAddress: s.order.contactInfo.emailAddress ?? s.order.customer.emailAddress,
            homePhone: s.order.contactInfo.homePhone,
            alternativePhone: s.order.contactInfo.alternativePhone,
            servicePhone: s.order.contactInfo.servicePhone,
            extension: s.order.contactInfo.extension,
            requestTextUpdates: s.order.contactInfo.requestTextUpdates ?? false,
            notesForTechnician: s.order.contactInfo.notesForTechnician
        }),
        scheduleDisplayText: (s) => {
            const dateModel = convertDateStringToDate(s.order.schedule.date);
            const readableDate = dateModel?.toLocaleDateString('en-us', {
                weekday: 'long',
                month: 'long',
                day: 'numeric',
                year: 'numeric'
            });

            const readableStartTime = militaryToTwelveHourTime(s.order.schedule.startTime);
            const readableEndTime = militaryToTwelveHourTime(s.order.schedule.endTime);

            const readableDuration = getDisplayTextForDurationLength(
                s.order.schedule.jobMinMinutes,
                s.order.schedule.jobMaxMinutes
            );

            return {
                date: readableDate,
                startTime: readableStartTime,
                endTime: readableEndTime,
                duration: readableDuration
            };
        },
        experimentOrder: (s) => {
            const ctuToUse = (s.order.serviceLocation.appointmentType === AppointmentTypeStrings.IN_SHOP
                || s.order.serviceLocation.appointmentType === AppointmentTypeStrings.DROP_OFF)
                ? s.order.serviceLocation.provider?.address?.zipCodeCtu : s.order.serviceLocation.zipCodeCtu;

            return {
                funnelVehicleYear: s.order.vehicle.year,
                funnelVehicleMake: s.order.vehicle.make,
                funnelVehicleModel: s.order.vehicle.model,
                funnelVehicleStyle: s.order.vehicle.style,
                funnelIsRepair: s.order.damage.isRepair,
                funnelNumberOfChips: s.order.damage.numberOfChips,
                funnelCarId: s.order.vehicle.carId,
                funnelServiceCity: s.order.serviceLocation.city,
                funnelServices: s.order.serviceLocation.state,
                funnelServiceZipCode: s.order.serviceLocation.zipCode,
                funnelServiceZipCodeCtu: ctuToUse,
                funnelParentAccountNumber: s.order.parentAccountNumber,
                funnelProviderNumber: s.providerNumber,
                funnelIsCoverageVerified: s.isVerified,
                funnelHasRecalibrationPart: getHasRecalibrationPart(s),
                funnelSelectedMultiGlass: s.order.damage.glassToReplace?.length > 1,
                funnelSelectedWindshieldGlass: getNonFalseValuesOfPropertyInArrayOfObjects(s.order.damage.glassToReplace, 'glassLocation')
                    .includes(damageLocationsSelected.WINDSHIELD),
                funnelSelectedBackGlass: getNonFalseValuesOfPropertyInArrayOfObjects(s.order.damage.glassToReplace, 'glassLocation')
                    .includes(damageLocationsSelected.REAR),
                funnelSelectedDriverSideGlass: getNonFalseValuesOfPropertyInArrayOfObjects(s.order.damage.glassToReplace, 'glassLocation')
                    .includes(damageLocationsSelected.DRIVER),
                funnelSelectedPassengerSideGlass: getNonFalseValuesOfPropertyInArrayOfObjects(s.order.damage.glassToReplace, 'glassLocation')
                    .includes(damageLocationsSelected.PASSENGER),
                funnelOrderPartNumbers: [
                    ...getNonFalseValuesOfPropertyInArrayOfObjects(
                        s.order.lineItems.glassParts,
                        'partNumber'
                    ),
                    ...getNonFalseValuesOfPropertyInArrayOfObjects(
                        s.order.lineItems.otherParts,
                        'partNumber'
                    )
                ],
                funnelOrderPartTypes: [
                    ...getNonFalseValuesOfPropertyInArrayOfObjects(
                        s.order.lineItems.glassParts,
                        'recalibrationType'
                    ),
                    ...getNonFalseValuesOfPropertyInArrayOfObjects(
                        s.order.lineItems.otherParts,
                        'recalibrationType'
                    )
                ]
            };
        },
        experimentSettings: (state) => state.applicationUser.experiments
            .filter((x) => !!x.isActive)
            .map((x) => x.settings)
            .reduce((r, c) => Object.assign(r, c), {}) ?? {},
        originalDeductible: (state) => (state.order.damage.isRepair ? state.order.originalDeductible.repair : state.order.originalDeductible.replace),
        currentDeductible: (state) => (state.order.damage.isRepair ? state.order.currentDeductible.repair : state.order.currentDeductible.replace)
    },
    actions:
    {
        // Content API Actions

        lookupVinByAddress({ licenseLastName, licenseStreetAddress, licenseZip, licenseState }) {
            return globalMethods.callHttpClient({
                method: endpoints.LookupVinByAddress.method,
                endpoint: endpoints.LookupVinByAddress.url,
                payload: {
                    licenseLastName,
                    licenseStreetAddress,
                    licenseZip,
                    licenseState
                }
            });
        },

        getRouteInfo(pageName) {
            return globalMethods.callHttpClient({
                method: endpoints.GetRouteInfo.method,
                endpoint: endpoints.GetRouteInfo.url(applicationConfig.APPLICATION_ABBREVIATION),
                payload: {
                    pageName
                }
            });
        },
        getHomepageName() {
            return globalMethods.callHttpClient({
                method: endpoints.GetHomepageInfo.method,
                endpoint: endpoints.GetHomepageInfo.url(applicationConfig.APPLICATION_ABBREVIATION)
            });
        },

        getPageData(pageName) {
            return globalMethods.callHttpClient({
                method: endpoints.GetPageData.method,
                endpoint: endpoints.GetPageData.url(applicationConfig.APPLICATION_ABBREVIATION, pageName),
                payload: {}
            });
        },

        // Vehicle API Actions
        getVehicleYears() {
            return globalMethods.callHttpClient({
                method: endpoints.GetVehicleYears.method,
                endpoint: endpoints.GetVehicleYears.url,
                payload: {}
            });
        },

        getVehicleMakes() {
            return globalMethods.callHttpClient({
                method: endpoints.GetVehicleMakes.method,
                endpoint: endpoints.GetVehicleMakes.url + this.order.vehicle.year,
                payload: {}
            });
        },

        getVehicleModels() {
            const encodedMake = encodeURIComponent(this.order.vehicle.make);
            return globalMethods.callHttpClient({
                method: endpoints.GetVehicleModels.method,
                endpoint: `${endpoints.GetVehicleModels.url}/${this.order.vehicle.year}/${encodedMake}`,
                payload: {}
            });
        },

        getVehicleStyles() {
            const encodedMake = encodeURIComponent(this.order.vehicle.make);
            const encodedModel = encodeURIComponent(this.order.vehicle.model);
            return globalMethods.callHttpClient({
                method: endpoints.GetVehicleStyles.method,
                endpoint: `${endpoints.GetVehicleStyles.url}/${this.order.vehicle.year}/${encodedMake}/${encodedModel}`,
                payload: {}
            });
        },

        getDamageOptions(carId) {
            return globalMethods.callHttpClient({
                method: endpoints.GetDamageOptions.method,
                endpoint: `${endpoints.GetDamageOptions.url}/${carId}`,
                payload: {}
            });
        },
        getIsVinbyAddressPermissible() {
            try {
                const response = globalMethods.callHttpClient({
                    method: endpoints.IsVinbyAddressPermissible.method,
                    endpoint: `${endpoints.IsVinbyAddressPermissible.url}?state=${this.order.customer.address.state}`,
                    payload: {}
                });
                return response;
            } catch (responseError) {
                return {
                    error: {
                        status: responseError.status
                    }
                };
            }
        },
        async getCoveragePolicyInfo() {
            const { order, issConfig, applicationUser } = this;
            const { policy } = order;

            if (!issConfig.isCoverageEnabled || applicationUser.coverageLookupAttempts > 10) {
                this.updateCoverageType(coverageType.NONE);
                return Promise.resolve();
            }

            this.applicationUser.coverageAttempts += 1;
            console.log(`Coverage lookup attempt #${this.applicationUser.coverageAttempts}. Max attempts allowed: 10.`);

            try {
                const response = await globalMethods.callHttpClient({
                    method: endpoints.CoveragePolicyInfo.method,
                    endpoint: endpoints.CoveragePolicyInfo.url,
                    payload: {
                        accountNumber: order.parentAccountNumber?.toString(),
                        policyNumber: policy.policyNumber,
                        dateOfLoss: policy.dateOfLoss,
                        zipCode: policy.policyZipCode,
                        referralCorrelationId: order.referralCorrelationId
                    }
                });

                const responsePolicy = response?.data?.policies?.[0];
                if (responsePolicy) {
                    this.updateCoverageType(coverageType.Deductible);
                    const insured = responsePolicy.insureds?.[0];

                    // populate parent account number
                    if (response.data.accountNumber) {
                        order.parentAccountNumber = parseInt(response.data.accountNumber, 10);
                    }

                    // populate policy holder details from policy lookup
                    order.customer.address.streetAddress = insured?.address;
                    order.customer.address.city = insured?.city;
                    order.customer.address.state = insured?.state;
                    order.customer.address.zipCode = insured?.zipCode?.toString();
                    order.customer.firstName = insured?.firstName;
                    order.customer.lastName = insured?.lastName;

                    // populate additional fields
                    order.policy.policyData = responsePolicy.policyData;

                    // populate vehicles
                    order.policy.vehicles = responsePolicy.vehicles ?? [];
                } else {
                    this.updateCoverageType(coverageType.NONE);
                }
                return Promise.resolve();
            } catch (e) {
                this.updateCoverageType(coverageType.NONE);
                return Promise.reject(e);
            }
        },
        clearDuplicateOrders() {
            this.applicationUser.duplicateOrders = [];
        },
        updateDuplicateCheckVisited(visited) {
            this.order.visitedDuplicateCheckPage = visited;
        },
        updateCoverageStatus(status) {
            this.order.insuranceCoverage.coverageStatus = status;
        },
        updateCoverageType(type) {
            this.order.insuranceCoverage.coverageType = type;
        },
        updateIsItacOptimized(isItacOptimized) {
            this.order.insuranceCoverage.isItacOptimized = isItacOptimized || false;
        },
        registerClaim() {
            const nonNumberCharRegex = /[^0-9]/g;
            const { order, isITAC } = this;
            return new Promise((resolve, reject) => {
                globalMethods.callHttpClient({
                    method: endpoints.RegisterClaim.method,
                    endpoint: endpoints.RegisterClaim.url,
                    payload:
                    {
                        referralCorrelationId: this.order.referralCorrelationId,
                        accountNumber: this.order.parentAccountNumber?.toString() ?? '',
                        policyData: this.order.policy.policyData,
                        isItac: isITAC,
                        insured: {
                            firstName: this.order.customer.firstName,
                            lastName: this.order.customer.lastName,
                            address: {
                                addressLine1: this.order.customer.address.streetAddress,
                                addressLine2: this.order.customer.address.streetAddress2,
                                city: this.order.customer.address.city,
                                state: this.order.customer.address.state,
                                zipCode: this.order.customer.address.zipCode,
                                country: 'US' // TODO set from store
                            },
                            homePhone: {
                                number: this.contactInfo.homePhone?.replaceAll(nonNumberCharRegex, '') ?? ''
                            }
                        },
                        driver: {
                            firstName: this.order.customer.firstName,
                            lastName: this.order.customer.lastName
                        },
                        caller: {
                            homePhone: {}
                        },
                        policyInfo: {
                            policyNumber: this.order.policy.policyNumber,
                            safelitePolicy: {
                                policies: []
                            },
                            actualDeductible: this.currentDeductible.toString() ?? ''
                        },
                        lossInfo: {
                            dateOfLoss: this.order.policy.dateOfLoss,
                            location: {
                                city: this.order.policy.damageCity,
                                state: this.order.policy.damageState,
                                country: 'US' // TODO set from store
                            },
                            vehicle: {
                                id: this.order.vehicle.policyVehicleId?.toString() ?? '',
                                year: this.order.vehicle.year?.toString() ?? '',
                                make: this.order.vehicle.make,
                                model: this.order.vehicle.model,
                                vin: this.order.vehicle.vin
                            },
                            cause: this.order.policy.damageCause,
                            damageDescription: this.order.policy.damageCause
                        }
                    }
                }).then((response) => {
                    this.order.insuranceCoverage.claimNumber = response.data.claimNumber;
                    if (response.data.isSuccess) {
                        this.updateCoverageStatus(coverageStatuses.VERIFIED);
                    } else {
                        this.updateCoverageStatus(coverageStatuses.NO_COVERAGE);
                    }
                    return resolve(response);
                }, (error) => {
                    this.updateCoverageStatus(coverageStatuses.NO_COVERAGE);
                    this.order.insuranceCoverage.claimNumber = null;
                    return reject(error);
                });
            });
        },
        getFinalDeductible() {
            const endorsementAnswersForPayload = [];
            const endorsementAnswers = this.order.policy.endorsementQuestionAnswers;
            if (endorsementAnswers) {
                endorsementAnswers.forEach((endorsement) => {
                    if (endorsement.selectedAnswer === 'Yes') {
                        endorsementAnswersForPayload.push(endorsement.endorsementName);
                    }
                });
            }

            const manualGlassNamesArray = [];
            const glassInformation = this.order.damage.glassToReplace;
            glassInformation?.forEach((glassPiece) => {
                manualGlassNamesArray.push(glassPiece?.glassLocation?.toUpperCase());
            });

            return new Promise((resolve, reject) => {
                globalMethods.callHttpClient({
                    method: endpoints.FinalDeductible.method,
                    endpoint: endpoints.FinalDeductible.url,
                    payload: {
                        referralCorrelationId: this.order.referralCorrelationId,
                        accountNumber: this.order.parentAccountNumber?.toString() ?? '',
                        endorsements: endorsementAnswersForPayload,
                        manualGlassNames: manualGlassNamesArray,
                        policyState: this.order.customer.address.state,
                        status: this.order.policy.status,
                        originalDeductible: this.originalDeductible,
                        currentDeductible: this.currentDeductible,
                        noCoverage: false,
                        isRepair: this.order.damage.isRepair,
                        policyNumber: this.order.policy.policyNumber,
                        insuredFirstName: this.order.customer.firstName,
                        insuredLastName: this.order.customer.lastName,
                        insuredZipCode: this.order.customer.address.zipCode,
                        policyVehicleId: this.order.vehicle.policyVehicleId?.toString() ?? '',
                        vehicleVin: this.order.vehicle.vin,
                        policyData: this.order.policy.policyData,
                        isItac: this.isITAC
                    }
                }).then((r) => {
                    this.order.policy.policyData = r.data.policyData;
                    this.updateDeductible(r.data);
                    return resolve(r);
                }).catch((error) => reject(error));
            });
        },

        getDuplicateReferrals() {
            const params = new URLSearchParams({
                parentAccountNumber: this.order.parentAccountNumber,
                customerPhoneNumber: this.order.contactInfo.servicePhone,
                policyNumber: this.order.policy.policyNumber,
                emailAddress: this.order.customer.emailAddress,
                dateOfLoss: this.order.policy.dateOfLoss
            });

            return new Promise((resolve, reject) => {
                globalMethods.callHttpClient({
                    method: endpoints.DuplicateSearch.method,
                    endpoint: `${endpoints.DuplicateSearch.url}?${params.toString()}`
                }).then((r) => {
                    this.applicationUser.duplicateOrders = r.data ?? [];
                    return resolve(r.data);
                }).catch((error) => {
                    this.applicationUser.duplicateOrders = [];
                    return reject(error);
                });
            });
        },
        async lookupVinByPlate(licensePlate, licenseState) {
            try {
                const response = await globalMethods.callHttpClient({
                    method: endpoints.LookupVinByPlate.method,
                    endpoint: endpoints.LookupVinByPlate.url,
                    payload: {
                        licensePlate,
                        licenseState
                    }
                });

                return response;
            } catch (responseError) {
                return {
                    error: {
                        status: responseError.status
                    }
                };
            }
        },

        // PartsOrQuestions API Actions
        async getPartsOrQuestions() {
            this.resetPartsAndDependencies();

            const { vehicle } = this;
            const { damage } = this;
            const { order } = this;

            const { carId } = vehicle;
            const glassArray = damage.glassToReplace;
            const zipCode = vehicle.registration.zipCode ? vehicle.registration.zipCode : order.customer.address.zipCode;
            const { vin } = vehicle;

            // create a new array to avoid mutating state
            const glassArrayForPayload = convertGlassPieceNamingForApi(glassArray);

            const response = await globalMethods.callHttpClient({
                method: endpoints.GetPartsOrQuestions.method,
                endpoint: endpoints.GetPartsOrQuestions.url,
                payload: {
                    carId,
                    glassPieces: glassArrayForPayload,
                    zip: zipCode,
                    vin,
                    oemEndorsementFlag: this.hasOemEndorsement
                }
            });

            // Flatten location and name properties
            response.data.partsOrQuestions = convertGlassPieceNamingFromApi(response.data.partsOrQuestions);

            return response;
        },

        async getParts() {
            const { vehicle } = this.order;
            const { damage } = this.order;
            const { order } = this;

            const { carId } = vehicle;
            const glassArray = damage.glassToReplace;
            const resultsArray = damage.partQuestionAnswers;
            const zipCode = vehicle.registration.zipCode ? vehicle.registration.zipCode : order.customer.address.zipCode;
            const { vin } = vehicle;

            // create a new array to avoid mutating state
            const glassArrayForPayload = convertGlassPieceNamingForApi(glassArray);
            const resultsArrayForPayload = convertResultsForApi(resultsArray);

            const response = await globalMethods.callHttpClient({
                method: endpoints.GetParts.method,
                endpoint: endpoints.GetParts.url,
                payload: {
                    carId,
                    glassPieces: glassArrayForPayload,
                    answerResults: resultsArrayForPayload,
                    zip: zipCode,
                    vin,
                    oemEndorsementFlag: this.hasOemEndorsement
                }
            });

            // Flatten location and name properties
            response.data.glassPieceParts = convertGlassPieceNamingFromApi(response.data.glassPieceParts);

            return response;
        },

        getCapabilityQuestions(carId, partNumber) {
            return globalMethods.callHttpClient({
                method: endpoints.GetCapabilityQuestions.method,
                endpoint: `${endpoints.GetCapabilityQuestions.url}/${carId}/${partNumber}`
            });
        },

        async updatePartFromCapabilityQuestionAnswer(part, capabilityQuestionAnswersForPart) {
            return (await globalMethods.callHttpClient({
                method: endpoints.GetPartFromCapabilityAnswer.method,
                endpoint: endpoints.GetPartFromCapabilityAnswer.url,
                payload: {
                    part,
                    capabilityAnswerResults: capabilityQuestionAnswersForPart
                }
            })).data[0];
        },
        getMobilePremiumFee() {
            const damageType = this.damage.isRepair ? 'Repair' : 'Replace';
            const paymentType = 'Insurance';

            return globalMethods.callHttpClient({
                method: endpoints.GetMobilePremiumFee.method,
                endpoint: `${endpoints.GetMobilePremiumFee.url}/${paymentType}/${damageType}`,
                logApiCall: true
            });
        },
        getMobileTimeSlots(startDate, endDate, zipCodeOverride = null) {
            const { order } = this;
            const { vehicle } = this.order;
            let lineItems = [
                ...(order.lineItems.supportingItems ?? []),
                ...(order.lineItems.vaps ?? []),
                ...(order.lineItems.glassParts ?? [])
            ];
            lineItems = getLineItemsFlattened(lineItems);
            lineItems = lineItems.map((lineItem) => ({
                partNumber: lineItem.partNumber,
                partType: lineItem.partType
            }));
            const glassPieces = order.damage.glassToReplace
                ? convertGlassPieceToBackEndCompatibleFormat(order.damage.glassToReplace)
                : [];
            const payload = {
                startDate,
                endDate,
                applicationName: applicationConfig.APPLICATION_NAME,
                billToAccountNumber: this.billToAccountNumber,
                parentAccountNumber: order.parentAccountNumber, // this.payment.parentAccountNumber,
                carId: vehicle.carId,
                lineItems,
                glassPieces,
                eon: order.eon,
                coverage: {
                    status: '',
                    deductible: 0,
                    additionalAuthFlag: ''
                },
                partSelection: {
                    hasAnsweredPartQuestions: !!order.damage.partQuestionAnswers?.length,
                    hasAnsweredMoldingQuestions: !!order.damage.moldingQuestionAnswers?.length,
                    hasAnsweredCapabilityQuestions: !!order.damage.capabilityQuestionAnswers?.length,
                    hasManuallySelectedParts:
                        !!this.applicationUser.pageData['vehicle-parts']?.partsOrQuestions
                            .length
                },
                vehicle: {
                    year: vehicle.year,
                    make: vehicle.make,
                    model: vehicle.model,
                    style: vehicle.style,
                    vin: vehicle.vin ?? ''
                },
                zipCode: zipCodeOverride ?? order.serviceLocation.zipCode
            };

            return globalMethods.callHttpClient({
                method: endpoints.GetMobileTimeSlots.method,
                endpoint: endpoints.GetMobileTimeSlots.url,
                payload,
                logApiCall: true,
                additionalSuccessEventDataHandler: (response) =>
                    getTimeSlotsAdditionalEventData(
                        response.data.provisionalTriggers,
                        zipCodeOverride ?? order.serviceLocation.zipCode,
                        response.data.days?.[0]?.date
                    )
            });
        },
        getShopTimeSlots(startDate, endDate, shopAppointmentType, providerNumber) {
            const { order } = this;
            const { vehicle } = this.order;

            let lineItems = [
                ...(order.lineItems.supportingItems ?? []),
                ...(order.lineItems.vaps ?? []),
                ...(order.lineItems.glassParts ?? [])
            ];
            lineItems = getLineItemsFlattened(lineItems);
            lineItems = lineItems.map((lineItem) => ({
                partNumber: lineItem.partNumber,
                partType: lineItem.partType
            }));
            const glassPieces = order.damage.glassToReplace
                ? convertGlassPieceToBackEndCompatibleFormat(order.damage.glassToReplace)
                : [];
            const payload = {
                providerNumber,
                startDate,
                endDate,
                shopAppointmentType,
                applicationName: applicationConfig.APPLICATION_NAME,
                billToAccountNumber: this.billToAccountNumber,
                parentAccountNumber: this.order.parentAccountNumber, // this.payment.parentAccountNumber,
                carId: vehicle.carId,
                lineItems,
                glassPieces,
                eon: order.eon,
                coverage: {
                    status: '',
                    deductible: 0,
                    additionalAuthFlag: ''
                },
                partSelection: {
                    hasAnsweredPartQuestions: !!order.damage.partQuestionAnswers?.length,
                    hasAnsweredMoldingQuestions: !!order.damage.moldingQuestionAnswers?.length,
                    hasAnsweredCapabilityQuestions: !!order.damage.capabilityQuestionAnswers?.length,
                    hasManuallySelectedParts: !!this.applicationUser.pageData['vehicle-parts']?.partsOrQuestions.length
                },
                vehicle: {
                    year: vehicle.year,
                    make: vehicle.make,
                    model: vehicle.model,
                    style: vehicle.style,
                    vin: vehicle.vin ?? ''
                }
            };

            return globalMethods.callHttpClient({
                method: endpoints.GetShopTimeSlots.method,
                endpoint: endpoints.GetShopTimeSlots.url,
                payload,
                additionalSuccessEventDataHandler: (response) => provisionalTriggersToString(response.data.provisionalTriggers)
            });
        },
        async getWipers() {
            const { carId } = this.order.vehicle;
            const serviceZipCode = this.order.serviceLocation.zipCode;

            return globalMethods
                .callHttpClient({
                    method: endpoints.GetWipers.method,
                    endpoint: `${endpoints.GetWipers.url}/${carId}/${serviceZipCode}`
                })
                .catch((error) => {
                // The wiper service sometimes returns 500s on legitimate carId/zipCode combination - return empty array instead of breaking flow
                    console.error(error);
                    return [];
                });
        },

        async getRainDefense() {
            return globalMethods
                .callHttpClient({
                    method: endpoints.GetRainDefense.method,
                    endpoint: `${endpoints.GetRainDefense.url}`
                })
                .catch((error) => {
                // The wiper service sometimes returns 500s on legitimate carId/zipCode combination - return empty array instead of breaking flow
                    console.error(error);
                    return [];
                });
        },

        getProviders(serviceZipCode, shopRadiusInMiles = 100) {
            const { carId, isBigTruck } = this.order.vehicle;
            const damageType = this.damage.isRepair ? 'Repair' : 'Replace';
            const { parentAccountNumber } = this.order;
            const partsWithRecal = getTopLevelGlassPartsWithRecal(this.order.lineItems.glassParts);
            const windshieldPartWithRecal = partsWithRecal?.length > 0 ? partsWithRecal[0] : null;
            const safeliteOnly = true;

            let url = `${endpoints.GetProviders.url}/${serviceZipCode}/${damageType}/${shopRadiusInMiles}/${parentAccountNumber}/${safeliteOnly}/${carId}`;
            if (windshieldPartWithRecal) {
                url += `/${windshieldPartWithRecal.partNumber}`;
            }
            url += `/${isBigTruck}`;
            return globalMethods.callHttpClient({
                method: endpoints.GetProviders.method,
                endpoint: url
            });
        },

        getTpaProviders(zipCode, radius) {
            const { carId, isBigTruck } = this.order.vehicle;
            const damageType = this.damage.isRepair ? 'Repair' : 'Replace';
            const { parentAccountNumber } = this.order;
            const partsWithRecal = getTopLevelGlassPartsWithRecal(this.order.lineItems.glassParts);
            const windshieldPartWithRecal = partsWithRecal?.length > 0 ? partsWithRecal[0] : null;
            const safeliteOnly = false;

            let url = `${endpoints.GetProviders.url}/${zipCode}/${damageType}/${radius}/${parentAccountNumber}/${safeliteOnly}/${carId}`;
            if (windshieldPartWithRecal) {
                url += `/${windshieldPartWithRecal.partNumber}`;
            }
            url += `/${isBigTruck}`;

            return new Promise((resolve, reject) => {
                globalMethods.callHttpClient({
                    method: endpoints.GetProviders.method,
                    endpoint: url
                }).then((response) => resolve(response), (error) => reject(error));
            });
        },
        getCarrierAccountInfo() {
            return new Promise((resolve, reject) => {
                globalMethods.callHttpClient({
                    method: endpoints.GetAccountInfo.method,
                    endpoint: endpoints.GetAccountInfo.url + this.order.parentAccountNumber
                }).then((response) => {
                    this.order.carrierPhoneNumber = response.data.phoneNumber;
                    return resolve(response.data);
                }).catch((error) => reject(error));
            });
        },
        async getRecalParts() {
            const { glassParts } = this.lineItems;
            const { carId } = this.vehicle;
            const { parentAccountNumber, referralSequenceNumber } = this.order;
            const { zipCode } = this.order.serviceLocation;

            if (glassParts && glassParts.length > 0) {
                const recalPromises = [];
                glassParts.forEach((glassPart) => {
                    if (glassPart.requiresRecalibration) {
                        const partNumberChecked = glassPart.partNumber;
                        recalPromises.push(globalMethods
                            .callHttpClient({
                                method: endpoints.GetRecalParts.method,
                                endpoint: endpoints.GetRecalParts.url(
                                    carId,
                                    partNumberChecked,
                                    glassPart.recalibrationType,
                                    parentAccountNumber,
                                    zipCode,
                                    applicationConfig.APPLICATION_NAME,
                                    referralSequenceNumber
                                )
                            })
                            .then((response) => {
                                const recalResponse = response.data;
                                if (recalResponse && recalResponse.recalibrationParts && recalResponse.recalibrationParts.length > 0) {
                                    this.addGlassPartRecalibrationInfo(partNumberChecked, recalResponse.recalibrationParts[0]);
                                }
                            }));
                    }
                });
                await Promise.allSettled(recalPromises);
            }
        },
        addGlassPartRecalibrationInfo(partNumber, recalPartInformation) {
            const glassPart = this.lineItems.glassParts.find((gp) => gp.partNumber === partNumber);
            if (glassPart) {
                const recalChildPart = glassPart.childParts?.find((cp) => cp.partNumber === recalPartInformation.partNumber);
                if (!recalChildPart) {
                    if (!Array.isArray(glassPart.childParts) || !glassPart.childParts.length) {
                        glassPart.childParts = [];
                    }
                    glassPart.childParts.push(recalPartInformation);
                }
            }
        },
        async getGlassFees() {
            const { insuranceCoverage, vehicle } = this.order;
            const { glassParts } = this.lineItems;
            const { isRepair } = this.damage;
            const { defaultProviderNumber, provider, zipCode } = this.order.serviceLocation;
            const damageType = isRepair ? 'Repair' : 'Install';
            const facilityType = this.isMobileAppointment ? 'Mobile' : 'InShop';
            const providerToUse = provider?.providerNumber ?? defaultProviderNumber;
            const partNumberListQueryString = getPartNumbersListForQueryString(glassParts, 'PartNumbers');

            const params = new URLSearchParams({
                serviceType: damageType,
                facilityType,
                parentAccountNumber: this.order.parentAccountNumber,
                billToAccountNumber: this.billToAccountNumber,
                isPremiumAppointment: false,
                isItacOptimized: insuranceCoverage.isItacOptimized,
                zipCode,
                coverageStatus: coverageStatuses.mapToApi(insuranceCoverage.coverageStatus),
                coverageType: coverageType.mapToApi(insuranceCoverage.coverageType),
                providerNumber: providerToUse,
                carId: vehicle.carId
            });

            return globalMethods.callHttpClient({
                method: endpoints.GetGlassFees.method,
                endpoint: `${endpoints.GetGlassFees.url}?${params.toString()}${partNumberListQueryString}`
            });
        },
        async getSupportingItems() {
            const { glassParts } = this.lineItems;
            const { carId } = this.vehicle;
            const { isRepair, numberOfChips } = this.damage;

            return globalMethods
                .callHttpClient({
                    method: endpoints.GetSupportingItems.method,
                    endpoint: endpoints.GetSupportingItems.url,
                    payload: {
                        carId,
                        damageType: isRepair ? 'Repair' : 'Replace',
                        parentAccountNumber: applicationConfig.CASH_PARENT_ACCOUNT_NUMBER,
                        parts: glassParts ?? [],
                        numberOfRepairChips: isRepair ? numberOfChips : 0
                    }
                });
        },

        async getITACPriceOrderItems(availableLineItems) {
            const { policy, vehicle, contactInfo, serviceLocation, insuranceCoverage } = this.order;
            const response = await globalMethods
                .callHttpClient({
                    method: endpoints.GetITACPriceOrderItems.method,
                    endpoint: endpoints.GetITACPriceOrderItems.url,
                    payload: {
                        lineItems: getLineItemsFlattened(availableLineItems),
                        ServerData: this.order.lineItems.serverData,
                        Customer: {
                            PhoneNumber: contactInfo.servicePhone,
                            State: policy.damageState || this.order.customer.address.state,
                            ZipCode: policy.policyZipCode
                        },
                        Account: {
                            ParentAccountNumber: this.order.parentAccountNumber,
                            LineOfBusiness: 'PERSONAL'
                        },
                        Provider: {
                            ProviderNumber: this.providerNumber,
                            ProviderCtuNumber: serviceLocation.zipCodeCtu,
                            ProviderState: serviceLocation.state
                        },
                        Vehicle: {
                            CarId: vehicle.carId,
                            Year: vehicle.year,
                            Make: vehicle.make,
                            Model: vehicle.model
                        },
                        Insurance: {
                            Deductible: this.currentDeductible ?? 0,
                            PolicyNumber: policy.policyNumber,
                            CoverageStatus: insuranceCoverage.coverageStatus,
                            CoverageType: insuranceCoverage.coverageType
                        },
                        Order: {
                            Eon: this.order.eon,
                            ReferralNumber: this.order.referralNumber,
                            ReferralSequenceNumber: this.order.referralSequenceNumber,
                            ReferralDate: `${this.order.referralDate}Z`,
                            ServiceZipCode: serviceLocation.zipCode,
                            IsReplacement: !this.isRepair,
                            IsOEMRequest: this.hasOemEndorsement
                        }
                    }
                }).catch((error) => {
                    console.error(error);
                    throw error;
                });

            const { lineItems, serverData, isItac, primaryBillToNumber, partsWerePriced, isItacOptimized } = response.data;

            if (serverData) {
                this.order.lineItems.serverData = serverData;
            }

            if (partsWerePriced) {
                this.updateIsItacOptimized(isItacOptimized);
                if (isItac) {
                    // if the ITAC Pricing API call returns isItac = true then we should switch to ITAC coverage type
                    this.updateCoverageType(coverageType.ITAC);
                } else if (this.isITAC) {
                    // If the ITAC pricing API call returns isItac = false, and we are currently ITAC in the store then we should switch to deductible coverage type
                    this.updateCoverageType(coverageType.Deductible);
                }
            }

            if (primaryBillToNumber && primaryBillToNumber.length !== 0) {
                this.issConfig.billToAccountNumber = primaryBillToNumber;
            } else {
                await this.getBillToInfo();
            }

            if (lineItems) {
                const retAvailableLineItems = addPricesToLineItems(availableLineItems, lineItems);
                return retAvailableLineItems;
            }

            return availableLineItems;
        },

        async getCombinedQuote(availableLineItems) {
            if (availableLineItems && availableLineItems.length > 0) {
                const { vehicle, serviceLocation, policy, eon, referralNumber, referralDate, referralSequenceNumber, lineItems } = this.order;

                const availableLineItemsFiltered = availableLineItems.filter((lineItem) => !!(lineItem.partNumber));

                const lineItemsWithOnlyPartNumbers = availableLineItemsFiltered.map((lineItem) => ({ partNumber: lineItem.partNumber }));

                const payload = {
                    ParentAccountNumber: this.order.parentAccountNumber,
                    BillToAccountNumber: this.billToAccountNumber,
                    ProviderNumber: this.providerNumber,
                    CarId: vehicle.carId,
                    Make: vehicle.make,
                    Model: vehicle.model,
                    Year: vehicle.year,
                    EON: eon,
                    ZipCode: policy.policyZipCode,
                    State: this.order.customer.address.state,
                    ReferralNumber: referralNumber,
                    ReferralDate: referralDate,
                    ReferralSequenceNumber: referralSequenceNumber,
                    ServiceZipCode: serviceLocation.zipCode,
                    IsReplacement: !this.isRepair,
                    ServerData: lineItems.serverData,
                    LineItems: lineItemsWithOnlyPartNumbers,
                    FeatureToggles: getFeatureTogglesPayloadObject(this.experimentSettings)
                };

                const response = await globalMethods
                    .callHttpClient({
                        method: endpoints.GetCombinedQuote.method,
                        endpoint: endpoints.GetCombinedQuote.url,
                        payload
                    })
                    .catch((error) => {
                        console.error(error);
                        return [];
                    });

                const { lineItems: pricedLinedItems, serverData } = response.data;

                if (serverData) {
                    this.order.lineItems.serverData = serverData;
                }

                if (pricedLinedItems) {
                    return addPricesToLineItems(availableLineItems, pricedLinedItems);
                }
                return availableLineItems;
            }

            return [];
        },

        getMobileFeePart() {
            const { vehicle, insuranceCoverage } = this.order;

            const params = new URLSearchParams({
                serviceType: this.damage.isRepair ? 'Repair' : 'Install',
                facilityType: 'Mobile',
                parentAccountNumber: this.order.parentAccountNumber,
                billToAccountNumber: this.billToAccountNumber,
                isItacOptimized: insuranceCoverage.isItacOptimized,
                providerNumber: this.providerNumber,
                carId: vehicle.carId,
                coverageStatus: coverageStatuses.mapToApi(insuranceCoverage.coverageStatus),
                coverageType: coverageType.mapToApi(insuranceCoverage.coverageType)
            });

            return globalMethods.callHttpClient({
                method: endpoints.GetMobileFeePart.method,
                endpoint: `${endpoints.GetMobileFeePart.url}?${params.toString()}`
            });
        },

        getServiceabilityDetails({ serviceZipCode }) {
            const { vehicle, damage, parentAccountNumber, referralSequenceNumber, lineItems } = this.order;
            const { carId } = vehicle;
            const glassArray = convertGlassPieceNamingForApi(damage.glassToReplace);
            const lineItemParts = [...(lineItems.glassParts || []), ...(lineItems.supportingItems || [])].map((part) => ({
                partNumber: part.partNumber,
                recalibrationType: part.recalibrationType
            }));

            const params = buildURLSearchParams({
                applicationName: applicationConfig.APPLICATION_NAME,
                parentAccountNumber,
                referralSequenceNumber,
                zip: serviceZipCode,
                carId,
                glassPieces: glassArray,
                lineItems: lineItemParts
            });

            return globalMethods.callHttpClient({
                method: endpoints.GetServiceabilityDetails.method,
                endpoint: `${endpoints.GetServiceabilityDetails.url}?${params.toString()}`
            });
        },
        lookupVehicleByVin(vin) {
            return globalMethods.callHttpClient({
                method: endpoints.LookupVehicleByVin.method,
                endpoint: endpoints.LookupVehicleByVin.url,
                payload: {
                    vin
                }
            });
        },

        async setVehicle() {
            const encodedMake = encodeURIComponent(this.order.vehicle.make);
            const encodedModel = encodeURIComponent(this.order.vehicle.model);
            const encodedStyle = encodeURIComponent(this.order.vehicle.style);
            const response = await globalMethods
                .callHttpClient({
                    method: endpoints.GetVehicle.method,
                    endpoint: `${endpoints.GetVehicle.url}/${this.order.vehicle.year}/${encodedMake}/${encodedModel}/${encodedStyle}`,
                    payload: {}
                });
            this.updateVehicle(response.data);
            return response;
        },

        setSaveSessionInfo(response) {
            this.order.referralNumber = response.referralNumber;
            this.order.referralSequenceNumber = response.referralSequenceNumber;
            this.order.referralDate = response.referralDate;
            this.order.referralCorrelationId = response.referralCorrelationId;
            this.order.eon = response.eon;
            this.order.workOrderNumber = response.workOrderNumber;
            this.order.settledTenderAmount = response.settledTenderAmount;
            this.order.lockToken = response.lockToken;
            this.order.customerPortalLoginToken = response.customerPortalLoginToken;
            this.applicationUser.savedSessionId = response.savedSessionId;
            this.applicationUser.crmCustomerId = response.crmCustomerId.toString();
        },

        saveSession({ submitAfterSave, createWorkOrderNumberForPIA }) {
            const { vehicle, damage, policy, customer, contactInfo, payment,
                lineItems, serviceLocation, schedule, insuranceCoverage } = this.order;

            // We don't want to save the session for a loaded session until the car ID is set
            if (this.order.loadedFromDupeCheck && !vehicle.carId) {
                return Promise.resolve(null);
            }

            if (this.hasSubmittedOrder()) {
                return Promise.resolve(null);
            }

            const loadedFromDupeCheck = !!(this.order.loadedFromDupeCheck && !this.order.loadedSessionClearedPreviousData);
            const newGlassToReplace = convertGlassPieceNamingForApi(damage.glassToReplace);
            const shouldClearOnSubmit = this.isVerified && this.isDeductible;
            const payloadGlassParts = setClearOnSubmit(lineItems.glassParts, shouldClearOnSubmit);
            const payloadSupportingItems = setClearOnSubmit(lineItems.supportingItems, shouldClearOnSubmit);
            const payloadVapsItems = setClearOnSubmit(lineItems.vaps, shouldClearOnSubmit);
            const payloadFeeItems = setClearOnSubmit(lineItems.feeItems, shouldClearOnSubmit);

            const payload = {
                applicationUser: {
                    crmCustomerId: this.applicationUser.crmCustomerId,
                    experiments: this.applicationUser.experiments,
                    lastPage: this.applicationUser.lastPageVisited,
                    pageData: this.applicationUser.pageData,
                    savedSessionId: this.applicationUser.savedSessionId
                },
                vehicle: {
                    year: vehicle.year,
                    make: vehicle.make,
                    model: vehicle.model,
                    style: vehicle.style,
                    vin: vehicle.vin,
                    carId: vehicle.carId,
                    licensePlateNumber: vehicle.registration?.licensePlate
                },
                damage: {
                    numberOfChips: damage.numberOfChips,
                    glassToReplace: newGlassToReplace,
                    isRepair: damage.isRepair,
                    partQuestionAnswers: damage.partQuestionAnswers,
                    moldingQuestionAnswers: damage.moldingQuestionAnswers,
                    capabilityQuestionAnswers: damage.capabilityQuestionAnswers,
                    dateOfLoss: policy.dateOfLoss,
                    damageCause: policy.damageCause,
                    damageState: policy.damageState,
                    damageCity: policy.damageCity,
                    isDamageGlassOnly: policy.isDamageGlassOnly
                },
                policy: {
                    policyHolder: {
                        policyFirstName: customer.firstName,
                        policyLastName: customer.lastName,
                        policyPhoneNumber: contactInfo.servicePhone,
                        policyEmail: customer.emailAddress,
                        policyState: customer.address.state
                    },
                    policyNumber: policy.policyNumber,
                    policyZipCode: policy.policyZipCode,
                    originalDeductible: this.originalDeductible,
                    currentDeductible: this.currentDeductible,
                    OemEndorsement: this.hasOemEndorsement,
                    noCoverage: this.isNoComp,
                    isItac: this.isITAC
                },
                customer: {
                    address: {
                        streetAddress: customer.address?.streetAddress,
                        streetAddress2: customer.address?.streetAddress2,
                        city: customer.address?.city,
                        state: customer.address?.state,
                        zipCode: customer.address?.zipCode?.toString()
                    },
                    emailAddress: contactInfo.emailAddress || customer.emailAddress,
                    firstName: contactInfo.firstName || customer.firstName,
                    lastName: contactInfo.lastName || customer.lastName,
                    homePhone: contactInfo.extension && contactInfo.homePhone ? contactInfo.homePhone + contactInfo.extension : contactInfo.homePhone,
                    servicePhone: contactInfo.servicePhone,
                    alternativePhone: contactInfo.alternativePhone,
                    isSmsOptIn: contactInfo.requestTextUpdates ?? false
                },
                lineItems: {
                    glassParts: payloadGlassParts,
                    serverData: lineItems.serverData,
                    supportingItems: [...payloadSupportingItems, ...payloadFeeItems],
                    vaps: payloadVapsItems
                },
                insuranceCoverage: {
                    coverageType: insuranceCoverage.coverageType,
                    coverageStatus: insuranceCoverage.coverageStatus,
                    claimNumber: insuranceCoverage.claimNumber
                },
                payment: {
                    parentAccountNumber: this.order.parentAccountNumber ?? this.issConfig.parentAccountNumber,
                    billToAccountNumber: this.billToAccountNumber,
                    paypalToken: payment.paypalToken,
                    paymentMethod: payment.paymentMethod === paymentMethods.PayNow ? null : payment.paymentMethod,
                    nextGenSettledAmount: payment.nextGenSettledAmount,
                    CCToken: payment.creditCardToken
                },
                serviceLocation: {
                    address: {
                        streetAddress: serviceLocation.address,
                        city: serviceLocation.city,
                        state: serviceLocation.state,
                        zipCode: serviceLocation.zipCode,
                        zipCodeCtu: serviceLocation.zipCodeCtu
                    },
                    appointmentType: (serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE
                        || serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP)
                        ? AppointmentTypeStrings.MOBILE : serviceLocation.appointmentType,
                    isVehicleProtected: serviceLocation.isVehicleProtected,
                    provider: {
                        IsSafeliteProvider: serviceLocation?.IsSafeliteProvider,
                        providerNumber: this.providerNumber,
                        address: {
                            streetAddress: serviceLocation.provider?.address?.streetAddress,
                            city: serviceLocation.provider?.address?.city,
                            state: serviceLocation.provider?.address?.state,
                            zipCode: serviceLocation.provider?.address?.zipCode,
                            zipCodeCtu: serviceLocation.provider?.address?.zipCodeCtu
                        }
                    },
                    techNotes: contactInfo.notesForTechnician
                },
                schedule: {
                    date: schedule.date,
                    startTime: schedule.startTime,
                    endTime: schedule.endTime,
                    routeCode: schedule.routeCode,
                    jobMaxMinutes: schedule.jobMaxMinutes,
                    jobMinMinutes: schedule.jobMinMinutes
                },
                referralDate: this.order.referralDate,
                referralNumber: this.order.referralNumber?.toString(),
                referralCorrelationId: this.order.referralCorrelationId,
                referralSequenceNumber: this.order.referralSequenceNumber,
                eon: this.order.eon,
                submitToMainframe: !!this.order.referralNumber,
                createWorkOrderNumberForPIA,
                lockToken: this.order.lockToken,
                loadedFromDupeCheck,
                submitAfterSave: !!submitAfterSave
            };

            return new Promise((resolve, reject) => {
                globalMethods.callHttpClient({
                    method: endpoints.SaveSession.method,
                    endpoint: endpoints.SaveSession.url,
                    payload,
                    additionalSuccessEventDataHandler: () =>
                        `Email provided: ${customer.emailAddress ? 'true' : 'false'}`
                }).then((response) => {
                    if (loadedFromDupeCheck) {
                        this.order.loadedSessionClearedPreviousData = true;
                    }
                    resolve(response);
                }, (error) => reject(error));
            });
        },
        /**
         * @function getCookieValueByName
         * @param {object} payload
         * referralNumber: the sv2 referral's referralNumber
         * responseDate: the sv2 referral's referralDate or the responseDate associated with the returned duplicate-check record
         * parentAccountNumber: the client's parentAccountNumber associated with the sv2 referral
         * correlationId: the correlationId associated with the sv2 referral
         * @summary
         * Gets cookie value by name, returns empty string if not found.
         * @returns {object} returns the response object for the load session api, which returns the sv2 referral information
         */
        async getReferralByPayload(payload) {
            return await globalMethods.callHttpClient({
                method: endpoints.LoadSession.method,
                endpoint: endpoints.LoadSession.url,
                payload: {
                    referralNumber: payload.referralNumber,
                    referralDate: payload.responseDate,
                    parentAccountNumber: payload.parentAccountNumber,
                    referralCorrelationId: payload.correlationId
                }
            });
        },
        async loadSession(duplicate) {
            const { order } = this;
            const response = await globalMethods.callHttpClient({
                method: endpoints.LoadSession.method,
                endpoint: endpoints.LoadSession.url,
                payload: {
                    referralNumber: duplicate.referralNumber,
                    referralDate: duplicate.referralDate,
                    parentAccountNumber: order.parentAccountNumber,
                    referralCorrelationId: duplicate.correlationId
                }
            });
            const { data } = response;
            if (!data) {
                return;
            }

            if (data?.customer) {
                order.contactInfo.firstName = data?.customer?.firstName;
                order.contactInfo.lastName = data?.customer?.lastName;
                order.contactInfo.emailAddress = data?.customer?.emailAddress;
                order.contactInfo.extension = data?.customer?.homePhone?.slice(10);
                order.contactInfo.homePhone = data?.customer?.homePhone?.slice(0, 10);
                order.contactInfo.servicePhone = data?.customer?.servicePhone;
                order.contactInfo.alternativePhone = data?.customer?.alternativePhone;
                order.contactInfo.requestTextUpdates = data?.customer?.isSmsOptIn;

                if (data?.customer?.address) {
                    order.customer.address.streetAddress = data.customer?.address?.streetAddress;
                    order.customer.address.streetAddress2 = data.customer?.address?.streetAddress2;
                    order.customer.address.city = data.customer?.address?.city;
                    order.customer.address.state = data.customer?.address?.state;
                    order.customer.address.zipCode = data.customer?.address?.zipCode;
                }
            }

            if (data?.vehicle) {
                order.vehicle.year = data?.vehicle?.year;
                order.vehicle.make = data?.vehicle?.make;
                order.vehicle.model = data?.vehicle?.model;
                order.vehicle.style = data?.vehicle?.style;
            }

            if (this.isPolicyLookupSuccessful) {
                if (data.insuranceCoverage) {
                    order.insuranceCoverage.coverageType = data?.insuranceCoverage?.coverageType;
                    order.insuranceCoverage.coverageStatus = data?.insuranceCoverage?.coverageStatus;
                    order.insuranceCoverage.claimNumber = data?.insuranceCoverage?.claimNumber;
                } else if (data?.payment?.insuranceCoverage) {
                    if (data?.payment?.insuranceCoverage?.isVerified) {
                        order.insuranceCoverage.coverageStatus = coverageStatuses.VERIFIED;
                    }
                    order.insuranceCoverage.claimNumber = data?.payment?.insuranceCoverage?.claimNumber;
                }

                if (order.policy.vehicles.length !== 0 && data.vehicle?.carId) {
                    order.vehicle.registration.licensePlate = data?.vehicle?.licensePlateNumber;
                    if (data.vehicle.vin) {
                        const vehicle = order.policy.vehicles.find((v) => v.vin === data.vehicle.vin);
                        if (vehicle) {
                            const vehicleResponse = await this.lookupVehicleByVin(vehicle.vin);
                            if (vehicleResponse) {
                                this.updateVehicle({
                                    ...vehicleResponse.data,
                                    policyVehicleId: vehicle.id,
                                    vin: vehicle.vin
                                });
                                this.updateVehicleCoverage({
                                    noCoverage: noCoverageForSelectedVehicle(vehicle),
                                    deductible: deductibleForSelectedVehicle(vehicle),
                                    repairWaived: repairWaivedForSelectedVehicle(vehicle),
                                    endorsements: endorsementsForSelectedVehicle(vehicle)
                                });
                            }
                        }
                    }
                }
            }

            order.referralNumber = data?.referralNumber;
            order.referralDate = data?.referralDate;
            order.referralCorrelationId = data?.referralCorrelationId;
            order.referralSequenceNumber = data?.referralSequenceNumber;
            order.eon = data?.eon;
            order.loadedFromDupeCheck = true;
            order.loadedSessionClearedPreviousData = false;
        },
        async loadSessionFromCookie(cookie) {
            const { order, issConfig } = this;
            const response = await this.getReferralByPayload(cookie);
            const { data } = response;
            if (data) {
                order.customer.address.streetAddress = data.customer?.address?.streetAddress;
                order.customer.address.streetAddress2 = data.customer?.address?.streetAddress2;
                order.customer.address.city = data.customer?.address?.city;
                order.customer.address.state = data.customer?.address?.state;
                order.customer.address.zipCode = data.customer?.address?.zipCode;
                order.customer.emailAddress = data.customer?.emailAddress;

                order.contactInfo.firstName = data?.customer?.firstName;
                order.contactInfo.lastName = data?.customer?.lastName;
                order.contactInfo.emailAddress = data?.customer?.emailAddress;
                order.contactInfo.extension = data?.customer?.homePhone?.slice(10);
                order.contactInfo.homePhone = data?.customer?.homePhone?.slice(0, 10);
                order.contactInfo.servicePhone = data?.customer?.servicePhone;
                order.contactInfo.alternativePhone = data?.customer?.alternativePhone;
                order.contactInfo.requestTextUpdates = data?.customer?.isSmsOptIn;

                if (data.insuranceCoverage) {
                    order.insuranceCoverage.coverageType = data?.insuranceCoverage?.coverageType;
                    order.insuranceCoverage.coverageStatus = data?.insuranceCoverage?.coverageStatus;
                    order.insuranceCoverage.claimNumber = data?.insuranceCoverage?.claimNumber;
                } else if (data?.payment?.insuranceCoverage) {
                    if (data?.payment?.insuranceCoverage?.isVerified) {
                        order.insuranceCoverage.coverageStatus = coverageStatuses.VERIFIED;
                    }
                    order.insuranceCoverage.claimNumber = data?.payment?.insuranceCoverage?.claimNumber;
                } else {
                    order.customer.firstName = data?.customer?.firstName;
                    order.customer.lastName = data?.customer?.lastName;
                }

                if (order.policy.vehicles.length !== 0 && data.vehicle?.carId) {
                    order.vehicle.registration.licensePlate = data?.vehicle?.licensePlateNumber;
                    if (data.vehicle.vin) {
                        const vehicle = order.policy.vehicles.find((v) => v.vin === data.vehicle.vin);
                        if (vehicle) {
                            const vehicleResponse = await this.lookupVehicleByVin(vehicle.vin);
                            if (vehicleResponse) {
                                this.updateVehicle({
                                    ...vehicleResponse.data,
                                    policyVehicleId: vehicle.id,
                                    vin: vehicle.vin
                                });
                                this.updateVehicleCoverage({
                                    noCoverage: noCoverageForSelectedVehicle(vehicle),
                                    deductible: deductibleForSelectedVehicle(vehicle),
                                    repairWaived: repairWaivedForSelectedVehicle(vehicle),
                                    endorsements: endorsementsForSelectedVehicle(vehicle)
                                });
                            }
                        }
                    }

                    order.vehicle.year = data.vehicle.year;
                    order.vehicle.make = data.vehicle.make;
                    order.vehicle.model = data.vehicle.model;
                    order.vehicle.style = data.vehicle.style;
                }

                order.policy.damageCause = data?.policy?.damageCause;
                order.policy.damageCity = data?.policy?.damageCity;
                order.policy.damageState = data?.policy?.damageState;
                order.policy.dateOfLoss = data?.policy?.dateOfLoss;
                order.policy.isDamageGlassOnly = data?.policy?.isDamageGlassOnly;
                order.policy.policyNumber = data?.policy?.policyNumber;
                order.policy.policyZipCode = data?.policy?.policyZipCode;

                order.referralNumber = data?.referralNumber;
                order.referralDate = data?.referralDate;
                order.referralCorrelationId = data?.referralCorrelationId;
                order.referralSequenceNumber = data?.referralSequenceNumber;
                order.eon = data?.eon;
                order.workOrderId = data?.workOrderId;
                order.loadedFromCookie = true;
                order.visitedDuplicateCheckPage = true;
                order.loadedSessionClearedPreviousData = false;
                issConfig.enableContinueFromCookie = false;
                this.updateIsSafeliteProvider(data?.provider?.isSafeliteProvider);
            }

            return data;
        },
        updateCreditCardToken(token) {
            this.order.payment.creditCardToken.subscriptionId = token.subscriptionId;
            this.order.payment.creditCardToken.expMonth = token.expMonth;
            this.order.payment.creditCardToken.expYear = token.expYear;
            this.order.payment.creditCardToken.cardType = token.cardType;
            this.order.payment.creditCardToken.billToPostalCode = token.billToPostalCode;
            this.order.payment.creditCardToken.billToFirstName = token.billToFirstName;
            this.order.payment.creditCardToken.billToLastName = token.billToLastName;
            this.order.payment.creditCardToken.referenceNumber = token.referenceNumber;
            this.order.payment.creditCardToken.authCode = token.authCode;
            this.order.payment.creditCardToken.transactionId = token.transactionId;
            this.order.payment.creditCardToken.transReferenceNumber = token.transReferenceNumber;
            this.order.payment.creditCardToken.lastFour = token.lastFour;
        },
        updatePaypalToken(token) {
            this.order.payment.paypalToken = token;
        },
        setSaveSessionPromise(promise) {
            this.applicationUser.saveSessionPromise = promise;
        },

        clearSaveSessionPromise() {
            this.applicationUser.saveSessionPromise = null;
        },

        saveEndorsementQuestionAnswers(endorsementQuestionAnswersArray) {
            // if endorsement question answers have changed, reset question answers
            const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(this.order.policy.endorsementQuestionAnswers, 'result');
            const sortedEndorsementQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(endorsementQuestionAnswersArray, 'result');
            const haveEndorsementQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedEndorsementQuestionAnswersArray.length
                || !sortedPreviousResultsArray?.every((x, i) => x.result === sortedEndorsementQuestionAnswersArray[i].result);

            if (haveEndorsementQuestionAnswersChanged) {
                this.updateEndorsementQuestionAnswers(null);
            }

            this.updateEndorsementQuestionAnswers(endorsementQuestionAnswersArray);
        },

        saveVehicleDamage(isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount) {
            const selectedGlassPassedInSorted = selectedGlassToReplace.slice().sort();
            const isGlassToReplaceTheSame = this.order.damage.glassToReplace?.length === selectedGlassToReplace.length
                && this.order.damage.glassToReplace
                    .slice()
                    .sort()
                    .every((obj, index) => obj.glassLocation === selectedGlassPassedInSorted[index].glassLocation
                        && obj.glassName === selectedGlassPassedInSorted[index].glassName);
            const isWindshieldRepairTheSame = isWindshieldRepair === this.order.damage.isRepair;
            const isChipCountTheSame = selectedWindshieldChipCount === this.order.damage.numberOfChips;
            const isDamageChanging = !isGlassToReplaceTheSame || !isWindshieldRepairTheSame
                || (isWindshieldRepair && !isChipCountTheSame);

            if (isDamageChanging) {
            // Reset dependent state when changing
            // Was resetGlassPartsState, added dependencies for SSR-290
                this.resetPartsAndDependencies();

                // Save new values
                this.updateIsRepair(isWindshieldRepair);
                this.updateNumberOfChips(isWindshieldRepair ? parseInt(selectedWindshieldChipCount) : null);
                this.updateGlassToReplace(selectedGlassToReplace);
            }
        },

        updateRegistration(registrationInfo) {
            this.order.vehicle.registration.licensePlate = registrationInfo?.licensePlate;
            this.order.vehicle.registration.address = registrationInfo?.address;
            this.order.vehicle.registration.city = registrationInfo?.city;
            this.order.vehicle.registration.state = registrationInfo?.state;
            this.order.vehicle.registration.zipCode = registrationInfo?.zipCode;
            this.order.vehicle.registration.firstName = registrationInfo?.firstName;
            this.order.vehicle.registration.lastName = registrationInfo?.lastName;
        },
        updateServiceLocation(serviceLocationInfo) {
            this.order.serviceLocation.address = serviceLocationInfo.address;
            this.order.serviceLocation.address2 = serviceLocationInfo.address2;
            this.order.serviceLocation.city = serviceLocationInfo.city;
            this.order.serviceLocation.state = serviceLocationInfo.state;
            this.order.serviceLocation.zipCode = serviceLocationInfo.zipCode;
            this.order.serviceLocation.zipCodeCtu = serviceLocationInfo.zipCodeCtu;
            this.order.serviceLocation.appointmentType = serviceLocationInfo.appointmentType;
            this.order.serviceLocation.isVehicleProtected = serviceLocationInfo.isVehicleProtected;

            this.order.serviceLocation.provider = {
                providerNumber: serviceLocationInfo.provider?.providerNumber,
                address: {
                    streetAddress: serviceLocationInfo.provider?.address?.streetAddress,
                    city: serviceLocationInfo.provider?.address?.city,
                    state: serviceLocationInfo.provider?.address?.state,
                    zipCode: serviceLocationInfo.provider?.address?.zipCode,
                    zipCodeCtu: serviceLocationInfo.provider?.address?.zipCodeCtu
                },
                companyName: serviceLocationInfo.provider?.companyName,
                phoneNumber: serviceLocationInfo.provider?.phoneNumber
            };
            this.order.serviceLocation.searchFilter = serviceLocationInfo.searchFilter;
        },

        resetState() {
            Object.assign(this, getDefaultState());
        },

        resetRegistrationState() {
            this.order.vehicle.registration.licensePlate = null;
            this.order.vehicle.registration.address = null;
            this.order.vehicle.registration.city = null;
            this.order.vehicle.registration.state = null;
            this.order.vehicle.registration.zipCode = null;
            this.order.vehicle.registration.firstName = null;
            this.order.vehicle.registration.lastName = null;
        },
        resetServiceLocationAndDependencies() {
            this.resetServiceLocationAppointmentType();
            this.resetServiceLocationProvider();
            this.resetSchedule();
        },
        resetServiceLocationAppointmentType() {
            this.order.serviceLocation.appointmentType = null;
        },
        resetServiceLocationProvider() {
            this.order.serviceLocation.provider = {
                providerNumber: null,
                companyName: null,
                phoneNumber: null,
                address: {
                    streetAddress: null,
                    city: null,
                    state: null,
                    zipCode: null,
                    zipCodeCtu: null
                }
            };
        },
        resetServiceLocationMobileAddress() {
            this.order.serviceLocation.address = null;
            this.order.serviceLocation.address2 = null;
            this.order.serviceLocation.city = null;
            this.order.serviceLocation.state = null;
            this.order.serviceLocation.isVehicleProtected = null;
        },

        resetBailout() {
            this.updatePageData({
                page: issPageValues.BAILOUT_PAGE,
                data: null
            });
        },

        resetInsurance() {
            this.order.insuranceCoverage.coverageStatus = coverageStatuses.PENDING;
            this.order.insuranceCoverage.coverageType = coverageType.NONE;
            this.order.insuranceCoverage.isItacOptimized = false;
            this.order.insuranceCoverage.claimNumber = null;
        },
        updateGlassFees(feeData) {
            if (feeData == null) {
                this.order.lineItems.feeItems = null;
                return;
            }

            feeData.forEach((fee) => {
                if (fee.partNumber === partTypeStrings.MOBILE_FEE) {
                    this.updateMobileFee(fee);
                } else if (fee.partNumber === partNumberStrings.RECYCLE_FEE) {
                    this.updateRecycleFee(fee);
                } else {
                    this.addPartNumberFeeItem(fee, fee.partNumber);
                }
            });
        },
        updateSupportingItems(partsData) {
            if (partsData == null) {
                this.order.lineItems.supportingItems = [];
                return;
            }

            // Process Recycle Fee
            this.updateRecycleFee(partsData.find((rf) => rf.partNumber === partNumberStrings.RECYCLE_FEE));

            // Remove RecycleFee from supported items as it's saved in feeItems;
            this.order.lineItems.supportingItems = partsData.filter((i) => i.partNumber !== partNumberStrings.RECYCLE_FEE);
        },

        updateVaps(partsData) {
            this.order.lineItems.vaps = partsData;
        },

        updateMobileFee(fee) {
            const isMobileFeeHidden = getExperimentSettingValue(this.experimentSettings, experimentSettings.ISS_FEATURE_TOGGLE_IS_MOBILE_FEE_HIDDEN) === 'true';
            // Mobile Fee is only added for NO COMP or ITAC and is NOT hidden
            if (fee && this.isVerified && (this.isNoComp || this.isITAC) && !isMobileFeeHidden) {
                this.addPartTypeFeeItem(fee, partTypeStrings.MOBILE_FEE);
            } else {
                this.addPartTypeFeeItem(null, partTypeStrings.MOBILE_FEE);
            }
        },

        updateRecycleFee(fee) {
            const isRecycleFeeHidden = getExperimentSettingValue(this.experimentSettings, experimentSettings.ISS_FEATURE_TOGGLE_IS_RECYCLE_FEE_HIDDEN) === 'true';
            // Recycle Fee is only added for NO COMP or ITAC and has Windshield Replacement and is NOT hidden
            if (fee && this.isVerified && (this.isNoComp || this.isITAC) && this.hasWindshieldReplacement && !isRecycleFeeHidden) {
                this.addPartNumberFeeItem(fee, partNumberStrings.RECYCLE_FEE);
            } else {
                this.addPartNumberFeeItem(null, partNumberStrings.RECYCLE_FEE);
            }
        },

        addPartNumberFeeItem(feeItem, partNumber) {
            this.addFeeItem(feeItem, (fi) => fi.partNumber !== partNumber);
        },

        addPartTypeFeeItem(feeItem, partType) {
            this.addFeeItem(feeItem, (fi) => fi.partType !== partType);
        },

        addFeeItem(feeItem, filter) {
            let { feeItems } = this.order.lineItems;
            // Remove all fee items with the given filter
            feeItems = feeItems.filter(filter);
            if (feeItem) {
                feeItems.push(feeItem);
            }
            this.order.lineItems.feeItems = feeItems;
        },

        async setPriceAndSalesTaxForOrderLineItems() {
            let lineItemsToTax;
            if (this.isVerified && !this.isDeductible) {
                lineItemsToTax = [
                    ...(this.order.lineItems.supportingItems ?? []),
                    ...(this.order.lineItems.glassParts ?? []),
                    ...(this.order.lineItems.otherParts ?? []),
                    ...(this.order.lineItems.vaps ?? []),
                    ...(this.order.lineItems.feeItems ?? [])
                ];
            } else {
                lineItemsToTax = [
                    ...(this.order.lineItems.vaps ?? []),
                    ...(this.order.lineItems.feeItems ?? [])
                ];
            }

            if (lineItemsToTax && lineItemsToTax.length > 0) {
                await this.getTaxOrderItems(lineItemsToTax);
            }
        },

        updateVehicle(vehicle) {
            // Assuming that the method caller pass all the properties.
            // otherwise need to check for undefined for every property.
            if (this.order.vehicle.carId !== vehicle.carId
                || (!this.order.vehicle.vin && vehicle.vin)
                || (this.order.vehicle.vin && vehicle.vin && this.order.vehicle.vin !== vehicle.vin)) {
                this.order.vehicle.vin = vehicle.vin;
            }

            this.order.vehicle.policyVehicleId = vehicle.policyVehicleId;
            this.order.vehicle.carId = vehicle.carId;
            this.order.vehicle.category = vehicle.category;
            this.order.vehicle.year = vehicle.year;
            this.order.vehicle.make = vehicle.make;
            this.order.vehicle.model = vehicle.model;
            this.order.vehicle.style = vehicle.style;
            this.order.vehicle.imageUrl = vehicle.imageUrl;
            this.order.vehicle.imageVifNumber = vehicle.imageVifNumber;
            this.order.vehicle.imageColor = vehicle.imageVifColor;
            this.order.vehicle.isBigTruck = vehicle.isBigTruck;
            this.order.vehicle.canSafeliteService = vehicle.canSafeliteService;

            this.updateSupportingItems(null);
            this.updateVaps(null);
        },

        updateVehicleCoverage(coverage) {
            if (coverage.noCoverage) {
                if (this.isNoCompQuoteEnabled) {
                    this.updateCoverageType(coverageType.NO_COMP);
                } else {
                    this.updateCoverageType(coverageType.NONE);
                }
            } else {
                this.updateCoverageType(coverageType.Deductible);
            }

            if (!this.isClaimRegistrationRequired) {
                this.updateCoverageStatus(coverageStatuses.VERIFIED);
            }

            this.order.policy.deductible.replace = coverage.deductible;
            this.order.policy.deductible.repair = coverage?.repairWaived ?? false ? 0 : coverage.deductible;
            this.order.policy.endorsements = coverage?.endorsements;

            this.order.originalDeductible.replace = this.order.policy.deductible.replace;
            this.order.currentDeductible.replace = this.order.policy.deductible.replace;
            this.order.originalDeductible.repair = this.order.policy.deductible.repair;
            this.order.currentDeductible.repair = this.order.policy.deductible.repair;
        },

        resetOrder() {
            this.order.referralNumber = null;
            this.order.referralSequenceNumber = null;
            this.order.referralDate = null;
            this.order.referralSequenceNumber = null;
            this.order.workOrderId = null;
            this.order.workOrderNumber = null;
            this.order.settledTenderAmount = null;
            this.order.lockToken = null;
            this.order.eon = null;
            this.order.originalDeductible.repair = null;
            this.order.originalDeductible.replace = null;
            this.order.currentDeductible.repair = null;
            this.order.currentDeductible.replace = null;
            this.order.loadedFromDupeCheck = null;
            this.order.loadedSessionClearedPreviousData = null;
            this.order.availableVaps = null;
            this.order.carrierPhoneNumber = null;
            this.order.customerPortalLoginToken = null;
            this.order.loadedFromCookie = false;
            this.order.visitedDuplicateCheckPage = false;
        },

        resetPolicy() {
            this.order.policy.policyNumber = null;
            this.order.policy.policyZipCode = null;
            this.order.policy.dateOfLoss = null;
            this.order.policy.damageCause = null;
            this.order.policy.damageCity = null;
            this.order.policy.damageState = null;
            this.order.policy.vehicles = [];
            this.order.policy.endorsements = [];
            this.order.policy.endorsementQuestionAnswers = [];
            this.order.policy.policyData = null;
            this.order.policy.deductible.repair = null;
            this.order.policy.deductible.replace = null;
        },

        resetPayment() {
            this.order.payment.parentAccountNumber = 0;
            this.order.payment.nextGenSettledAmount = 0;
            this.order.payment.paymentMethod = null;
            this.order.payment.paypalToken = null;
            this.order.payment.creditCardToken.subscriptionId = null;
            this.order.payment.creditCardToken.expMonth = null;
            this.order.payment.creditCardToken.expYear = null;
            this.order.payment.creditCardToken.cardType = null;
            this.order.payment.creditCardToken.billToPostalCode = null;
            this.order.payment.creditCardToken.billToFirstName = null;
            this.order.payment.creditCardToken.billToLastName = null;
            this.order.payment.creditCardToken.referenceNumber = null;
            this.order.payment.creditCardToken.authCode = null;
            this.order.payment.creditCardToken.transactionId = null;
            this.order.payment.creditCardToken.transReferenceNumber = null;
            this.order.payment.creditCardToken.lastFour = null;
        },

        resetCustomer() {
            this.order.customer.emailAddress = null;
            this.order.customer.firstName = null;
            this.order.customer.lastName = null;
            this.order.customer.address.city = null;
            this.order.customer.address.state = null;
            this.order.customer.address.zipCode = null;
            this.order.customer.address.streetAddress = null;
            this.order.customer.address.streetAddress2 = null;
        },

        resetContactInfo() {
            this.order.contactInfo.firstName = null;
            this.order.contactInfo.lastName = null;
            this.order.contactInfo.emailAddress = null;
            this.order.contactInfo.homePhone = null;
            this.order.contactInfo.alternativePhone = null;
            this.order.contactInfo.servicePhone = null;
            this.order.contactInfo.extension = null;
            this.order.contactInfo.requestTextUpdates = false;
            this.order.contactInfo.notesForTechnician = '';
        },

        resetVehicleState() {
            this.order.vehicle.policyVehicleId = null;
            this.order.vehicle.year = null;
            this.order.vehicle.make = null;
            this.order.vehicle.model = null;
            this.order.vehicle.style = null;
            this.order.vehicle.carId = null;
            this.order.vehicle.category = null;
            this.order.vehicle.vin = null;
            this.order.vehicle.imageUrl = null;
            this.order.vehicle.imageVifNumber = null;
            this.order.vehicle.imageColor = null;
            this.order.vehicle.registration.licensePlate = null;
            this.order.vehicle.registration.state = null;
            this.order.vehicle.registration.address = null;
            this.order.vehicle.registration.city = null;
            this.order.vehicle.registration.zipCode = null;
            this.order.vehicle.registration.firstName = null;
            this.order.vehicle.registration.lastName = null;
            this.order.vehicle.isBigTruck = null;
            this.order.vehicle.canSafeliteService = null;

            if (this.isBailout && this.bailoutCode === bailoutCode.HeavyTruckVehicle) {
                this.resetBailout();
            }
        },

        resetGlassPartsState() {
            this.order.lineItems.glassParts = null;
            this.order.lineItems.supportingItems = [];
            this.order.lineItems.vaps = null;
            this.order.lineItems.feeItems = [];
            this.order.lineItems.serverData = null;
            this.order.damage.partQuestionAnswers = null;
            this.order.damage.moldingQuestionAnswers = null;
            this.order.damage.capabilityQuestionAnswers = null;
            this.applicationUser.pageData[issPageValues.PART_QUESTIONS] = null;
            this.applicationUser.pageData[issPageValues.VEHICLE_PARTS] = null;
            this.applicationUser.pageData[issPageValues.MOLDING_QUESTIONS] = null;
            this.applicationUser.pageData[issPageValues.CAPABILITY_QUESTIONS] = null;
        },
        resetSchedule() {
            this.order.schedule.date = null;
            this.order.schedule.startTime = null;
            this.order.schedule.endTime = null;
            this.order.schedule.routeCode = null;
            this.order.schedule.jobMaxMinutes = null;
            this.order.schedule.jobMinMinutes = null;
        },
        resetDamageState() {
            this.order.damage.isRepair = null;
            this.order.damage.numberOfChips = null;
            this.order.damage.glassToReplace = null;
        },

        resetISSConfigState() {
            this.issConfig.clientName = 'Generic Insurance';
            this.issConfig.clientFullName = 'Generic Insurance';
            this.issConfig.clientDisplayName = 'Generic Insurance';
            this.issConfig.clientHeader = {};
            this.issConfig.parentAccountNumber = 0;
            this.issConfig.styleSheet = '';
            this.issConfig.isCoverageEnabled = false;
            this.issConfig.isAuthenticated = false;
            this.issConfig.enableContinueFromCookie = false;
            this.issConfig.enableTPAFlow = false;
            this.issConfig.isClaimRegistrationRequired = false;
            this.issConfig.successReturnURL = null;
            this.issConfig.failureReturnURL = null;
            this.issConfig.disabledFields.policyNumber = false;
            this.issConfig.disabledFields.policyZipCode = false;
            this.issConfig.disabledFields.dateOfLoss = false;
            this.issConfig.siteType = null;
            this.issConfig.enableNoCompQuote = false;
            this.issConfig.billToAccountNumber = null;
        },

        disableKeyFields() {
            this.issConfig.disabledFields.policyNumber = true;
            this.issConfig.disabledFields.policyZipCode = true;
            this.issConfig.disabledFields.dateOfLoss = true;
        },

        updateVehicleYear(year) {
            if (this.order.vehicle.year !== year) {
                this.resetVehicleState();
                this.resetDamageAndDependencies();

                this.order.vehicle.year = year;
            }
        },

        updateVehicleMake(make) {
            if (this.order.vehicle.make !== make) {
                const { year } = this.order.vehicle;

                this.resetVehicleState();
                this.resetDamageAndDependencies();

                this.order.vehicle.year = year;
                this.order.vehicle.make = make;
            }
        },

        updateVehicleModel(model) {
            if (this.order.vehicle.model !== model) {
                const { year } = this.order.vehicle;
                const { make } = this.order.vehicle;

                this.resetVehicleState();
                this.resetDamageAndDependencies();

                this.order.vehicle.year = year;
                this.order.vehicle.make = make;
                this.order.vehicle.model = model;
            }
        },

        updateVehicleStyle(style) {
            if (this.order.vehicle.style !== style) {
                const { year } = this.order.vehicle;
                const { make } = this.order.vehicle;
                const { model } = this.order.vehicle;

                this.resetVehicleState();
                this.resetDamageAndDependencies();

                this.order.vehicle.year = year;
                this.order.vehicle.make = make;
                this.order.vehicle.model = model;
                this.order.vehicle.style = style;
            }
        },

        updateEndorsementQuestionAnswers(answersArray) {
            this.order.policy.endorsementQuestionAnswers = answersArray;
        },

        updateIsRepair(isRepair) {
            this.order.damage.isRepair = isRepair;
        },

        updateNumberOfChips(numberOfChips) {
            this.order.damage.numberOfChips = numberOfChips;
        },

        updateGlassToReplace(glassToReplace) {
            this.order.damage.glassToReplace = glassToReplace;
        },

        updateGlassParts(partsData) {
            this.order.lineItems.glassParts = partsData;
        },

        updateMoldingQuestionAnswers(answersArray) {
            this.order.damage.moldingQuestionAnswers = answersArray;
        },

        updateCapabilityQuestionAnswers(answersArray) {
            this.order.damage.capabilityQuestionAnswers = answersArray;
        },

        updatePartQuestionAnswers(answersArray) {
            this.order.damage.partQuestionAnswers = answersArray;
        },

        updatePageData(pageData) {
            this.applicationUser.pageData[pageData.page] = pageData.data;
        },
        updatePolicyData(welcomePageModel) {
            this.order.policy.policyNumber = welcomePageModel?.policyNumber;
            this.order.policy.policyZipCode = welcomePageModel?.policyZipCode;
            this.order.policy.dateOfLoss = welcomePageModel?.dateOfLoss;
            this.order.policy.damageCause = welcomePageModel?.damageCause;
            this.order.policy.damageState = welcomePageModel?.damageState;
            this.order.policy.damageCity = welcomePageModel?.damageCity;
            this.order.policy.isDamageGlassOnly = welcomePageModel?.isDamageGlassOnly;
            this.order.serviceLocation.zipCode = welcomePageModel?.policyZipCode;
            this.updatePhoneNumbers({
                home: welcomePageModel?.phoneNumber,
                service: welcomePageModel?.phoneNumber,
                extension: welcomePageModel?.extension
            });
        },
        updatePolicyHolderDetails(customerQuestions) {
            this.order.customer.address.streetAddress = customerQuestions.addressQuestions.streetAddress;
            this.order.customer.address.streetAddress2 = customerQuestions.addressQuestions.streetAddress2;
            this.order.customer.address.city = customerQuestions.addressQuestions.city;
            this.order.customer.address.state = customerQuestions.addressQuestions.state;
            this.order.customer.address.zipCode = customerQuestions.addressQuestions.zipCode;
            this.order.customer.firstName = customerQuestions.firstName;
            this.order.customer.lastName = customerQuestions.lastName;
            this.order.customer.emailAddress = customerQuestions.email;
            this.updatePhoneNumbers({
                home: customerQuestions.phoneNumber,
                service: customerQuestions.phoneNumber,
                extension: customerQuestions.extension
            });
            this.order.serviceLocation.zipCode = customerQuestions.addressQuestions.zipCode;
        },
        updateIsSafeliteProvider(isSafelite) {
            this.order.serviceLocation.IsSafeliteProvider = isSafelite;
        },
        updateDeductible(deductibleInfo) {
            if (this.order.damage.isRepair) {
                this.order.currentDeductible.repair = deductibleInfo.deductible;
            } else {
                this.order.currentDeductible.replace = deductibleInfo.deductible;
            }
        },
        savePartQuestionAnswers(partQuestionAnswersArray) {
        // if part question answers have changed, reset subsequent question answers
            const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(this.order.damage.partQuestionAnswers, 'result');
            const sortedPartQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(partQuestionAnswersArray, 'result');
            const havePartQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedPartQuestionAnswersArray.length
                || !sortedPreviousResultsArray?.every((x, i) => x.result === sortedPartQuestionAnswersArray[i].result);

            if (havePartQuestionAnswersChanged) {
                this.resetServiceLocationAndDependencies();

                this.updateGlassParts(null);
                this.updateMoldingQuestionAnswers(null);
                this.updateCapabilityQuestionAnswers(null);
                this.updateSupportingItems(null);
                this.updateVaps(null);

                this.updatePageData({ page: issPageValues.VEHICLE_PARTS, data: null });
                this.updatePageData({ page: issPageValues.MOLDING_QUESTIONS, data: null });
                this.updatePageData({ page: issPageValues.CAPABILITY_QUESTIONS, data: null });
            }

            // Save new values
            this.updatePartQuestionAnswers(partQuestionAnswersArray);
        },
        saveMoldingQuestionAnswers(moldingQuestionAnswersArray) {
            const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(this.order.damage.moldingQuestionAnswers, 'result');
            const sortedMoldingQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(moldingQuestionAnswersArray, 'result');
            const haveMoldingQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedMoldingQuestionAnswersArray.length
                || !sortedPreviousResultsArray?.every((x, i) => x.result === sortedMoldingQuestionAnswersArray[i].result);

            if (haveMoldingQuestionAnswersChanged) {
                this.resetServiceLocationAndDependencies();

                this.updateGlassParts(null);
                this.updateSupportingItems(null);
                this.updateCapabilityQuestionAnswers(null);
                this.updatePageData({ page: issPageValues.CAPABILITY_QUESTIONS, data: null });
            }

            // Save new values
            this.updateMoldingQuestionAnswers(moldingQuestionAnswersArray);
        },
        saveCapabilityQuestionAnswers(capabilityQuestionAnswersArray) {
            const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(this.order.damage.capabilityQuestionAnswers, 'result');
            const sortedCapabilityQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(capabilityQuestionAnswersArray, 'result');
            const haveCapabilityQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedCapabilityQuestionAnswersArray.length
                || !sortedPreviousResultsArray?.every((x, i) => x.result === sortedCapabilityQuestionAnswersArray[i].result);

            if (haveCapabilityQuestionAnswersChanged) {
                this.resetServiceLocationAndDependencies();

                this.updateGlassParts(null);
                this.updateSupportingItems(null);
            }

            // Save new values
            this.updateCapabilityQuestionAnswers(capabilityQuestionAnswersArray);
        },

        // Tax order actions
        async getTaxOrderItems(pricedLineItems) {
            const { order } = this;
            const { serviceLocation } = order;
            const { appointmentType } = serviceLocation;
            const serviceLocationCity = serviceLocation.city;
            const serviceLocationState = serviceLocation.state;
            const serviceLocationZipCode = serviceLocation.zipCode;
            const lineItemServerData = this.order.lineItems.serverData;

            const isMobileApt = appointmentType === AppointmentTypeStrings.MOBILE
                || appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP;

            const retPricedLineItems = await globalMethods.callHttpClient({
                method: endpoints.TaxOrderItems.method,
                endpoint: endpoints.TaxOrderItems.url,
                payload: {
                    ParentAccountNumber: this.order.parentAccountNumber,
                    BillToAccountNumber: this.billToAccountNumber,
                    ProviderNumber: this.providerNumber,
                    AppointmentType: appointmentType,
                    PricedLineItems: getLineItemsFlattened(pricedLineItems),
                    ServiceLocation: {
                        City: isMobileApt ? serviceLocationCity : null,
                        State: isMobileApt ? serviceLocationState : null,
                        ZipCode: isMobileApt ? serviceLocationZipCode : null
                    },
                    ServerData: lineItemServerData || ''
                }
            }).then((response) => {
                this.order.lineItems.serverData = response.data.serverData;
                return addTaxesToPricedLineItems(pricedLineItems, response.data.taxedLineItems);
            });

            return retPricedLineItems;
        },
        addEventToBus(event) {
            this.applicationUser.eventBus.push(event);
        },
        removeEventFromBus(eventData) {
            const matchedEvent = this.applicationUser.eventBus.find(({ category, subCategory }) => category === eventData.category && subCategory === eventData.subCategory);
            const itemIndex = this.applicationUser.eventBus.indexOf(matchedEvent);

            // If the item exists, remove it.
            if (itemIndex > -1) {
                this.applicationUser.eventBus.splice(itemIndex, 1);
            }
        },

        // populate initial state
        populateInitialState() {
            if (!localStorage.getItem(storeId)) {
                this.$state = state;
            }
        },

        // Location API Actions
        getAlertReasonsByCtu(ctu) {
            return globalMethods.callHttpClient({
                method: endpoints.GetAlertReasons.method,
                endpoint: `${endpoints.GetAlertReasons.url}/${ctu}`,
                payload: {},
                logApiCall: true
            });
        },

        // Schedule Actions
        saveSchedule(scheduleInfo) {
            this.updateSchedule(scheduleInfo);
        },
        updateSchedule(scheduleInfo) {
            if (scheduleInfo) {
                this.order.schedule.date = scheduleInfo.date;
                this.order.schedule.startTime = scheduleInfo.startTime;
                this.order.schedule.endTime = scheduleInfo.endTime;
                this.order.schedule.routeCode = scheduleInfo.routeCode;
                this.order.schedule.jobMaxMinutes = scheduleInfo.jobMaxMinutes;
                this.order.schedule.jobMinMinutes = scheduleInfo.jobMinMinutes;
            }
        },
        // Analytics Actions
        logExperimentExposure(pageName, experiment) {
            return globalMethods.callHttpClient({
                method: endpoints.LogExperimentExposureIfAssigned.method,
                endpoint: endpoints.LogExperimentExposureIfAssigned.url,
                payload: {
                    experimentForLogging: {
                        userId: getUserIdValue(),
                        deviceId: getDeviceIdValue(),
                        experimentUniverseId: experiment.universeId,
                        experimentUniverseName: experiment.universeName,
                        experimentTestId: experiment.testId,
                        experimentTestName: experiment.testName,
                        experimentVariationId: experiment.variationId,
                        experimentVariationName: experiment.variationName,
                        enabled: experiment.isActive,
                        isExposed: experiment.isExposed,
                        userPartitionNumber: experiment.userPartitionNumber,
                        assignmentId: experiment.assignmentId,
                        sessionKey: getSessionKeyValue(),
                        pageName
                    }
                }
            });
        },
        logExperimentIfExists(pageName, universe) {
            const experiment = this.applicationUser.experiments.find((e) => e.universeName === universe);
            if (experiment !== undefined) {
                this.logExperimentExposure(pageName, experiment);
            }
        },
        logPageView({ userId, sessionKey, pageName, sessionId, action, event, shouldUseSessionId, experimentsForUser }) {
            const payload = {
                userId,
                sessionKey,
                sessionId,
                pageName,
                applicationName: applicationConfig.APPLICATION_NAME,
                action,
                event,
                shouldUseSessionId,
                experimentsForUser
            };

            return globalMethods.callHttpClient({
                method: endpoints.LogPageView.method,
                endpoint: endpoints.LogPageView.url,
                payload,
                logApiCall: false
            }).then(
                (response) => response,
                (error) => {
                    console.log(`Analytics Service Error: ${error.data}`);
                }
            );
        },
        logCustomEvent({ userId, sessionKey, pageName, sessionId, category, action, label, value, shouldUseSessionId, experimentsForUser }) {
            if (pageName == null || pageName.length === 0) { pageName = 'none'; }

            const payload = {
                userId,
                sessionKey,
                sessionId,
                pageName,
                applicationName: applicationConfig.APPLICATION_NAME,
                category,
                action,
                label,
                value,
                shouldUseSessionId,
                experimentsForUser
            };

            return globalMethods.callHttpClient({
                method: endpoints.LogCustomEvent.method,
                endpoint: endpoints.LogCustomEvent.url,
                payload,
                logApiCall: false
            }).then(
                (response) => response,
                (error) => {
                    console.log(`Analytics Service Error: ${error.data}`);
                }
            );
        },
        logWelcomePageExperiments(issPage) {
            this.logExperimentIfExists(issPage, experimentUniverses.ISS_FEATURETOGGLE_AREFEES_HIDDEN);
            this.logExperimentIfExists(issPage, experimentUniverses.ISS_FEATURETOGGLE_AREFEES_OVERRIDDEN);
        },
        initializeSession({ userId, sessionId, userAgent, referrer }) {
            const payload = {
                applicationName: applicationConfig.APPLICATION_NAME,
                userId,
                deviceId: userId,
                sessionId,
                userAgent,
                operatorId: 'WEB',
                userName: 'SafeliteISS',
                referrer
            };

            return globalMethods.callHttpClient({
                method: endpoints.InitializeSession.method,
                endpoint: endpoints.InitializeSession.url,
                payload,
                logApiCall: false
            }).then(
                (response) => response,
                (error) => {
                    console.log(`Analytics Service Error: ${error.data}`);
                }
            );
        },

        updateLastPageVisited(lastPageVisited) {
            this.applicationUser.lastPageVisited = lastPageVisited;
        },

        updateExperiments(experiments) {
            this.applicationUser.experiments = experiments;
        },
        updateTriggeredSiteEntry(wasSiteEntryTriggered) {
            this.applicationUser.triggeredSiteEntry = wasSiteEntryTriggered;
        },

        updateContactInfo(contactInfo) {
            this.order.contactInfo.firstName = contactInfo?.firstName ?? '';
            this.order.contactInfo.lastName = contactInfo?.lastName ?? '';
            this.order.contactInfo.emailAddress = contactInfo?.emailAddress ?? '';
            this.order.contactInfo.requestTextUpdates = contactInfo?.requestTextUpdates ?? false;
            this.order.contactInfo.notesForTechnician = contactInfo?.notesForTechnician ?? '';
        },

        updatePhoneNumbers(phoneNumbers) {
            const contact = this.order.contactInfo;
            contact.homePhone = phoneNumbers.home !== undefined ? phoneNumbers.home : contact.homePhone;
            contact.alternativePhone = phoneNumbers.alternative !== undefined ? phoneNumbers.alternative : contact.alternativePhone;
            contact.servicePhone = phoneNumbers.service !== undefined ? phoneNumbers.service : contact.servicePhone;
            contact.extension = phoneNumbers.extension !== undefined ? phoneNumbers.extension : contact.extension;
        },

        GetExperimentsByUser(userId) {
            return globalMethods.callHttpClient({
                method: endpoints.GetExperimentsByUser.method,
                endpoint: `${endpoints.GetExperimentsByUser.url}/${userId}`,
                payload: {}
            });
        },

        async runExperimentsForTrigger({ deviceId, triggerEvent, triggerValue }) {
            if (triggerEvent === experimentTriggers.SITE_ENTRY) {
                this.updateTriggeredSiteEntry(true);
            }

            const payload = {
                applicationName: applicationConfig.APPLICATION_NAME,
                deviceId,
                triggerEvent,
                triggerValue,
                experimentOrder: this.experimentOrder
            };

            const response = await globalMethods.callHttpClient({
                method: endpoints.RunExperimentsForTrigger.method,
                endpoint: endpoints.RunExperimentsForTrigger.url,
                payload
            });

            this.updateExperiments(response.data.experiments);
        },

        async validateZip({ zip }) {
            try {
                const response = await globalMethods.callHttpClient({
                    method: endpoints.ValidateZip.method,
                    endpoint: endpoints.ValidateZip.url(zip)
                });
                const zipInfo = response.data;
                if (zipInfo?.isValid === true) {
                    this.order.serviceLocation.zipCodeCtu = zipInfo.zipCodeCtu;
                    this.order.serviceLocation.defaultProviderNumber = zipInfo.providerNumber;
                    this.order.serviceLocation.state = zipInfo.state;
                    return Promise.resolve(zipInfo);
                }

                return Promise.reject(new Error('Invalid Zip Info'));
            } catch (e) {
                return Promise.reject(e);
            }
        },

        async validateMobileZip({ zip }) {
            const damageType = this.order.damage.isRepair ? 'Repair' : 'Replace';
            try {
                const response = await globalMethods.callHttpClient({
                    method: endpoints.ValidateZip.method,
                    endpoint: endpoints.ValidateMobileZip.url(zip, damageType)
                });
                const zipInfo = response.data;
                if (zipInfo?.isValid === true) {
                    return Promise.resolve(zipInfo);
                }

                return Promise.reject(new Error('Invalid Zip Info'));
            } catch (e) {
                return Promise.reject(e);
            }
        },

        async getBillToInfo() {
            const { order, issConfig } = this;
            try {
                const params = new URLSearchParams({
                    parentAccountNumber: order.parentAccountNumber.toString(),
                    providerNumber: this.providerNumber,
                    typeOfClaim: 'GLASS ONLY',
                    lineOfBusiness: 'PERSONAL',
                    isItac: this.isITAC
                });

                const response = await globalMethods.callHttpClient({
                    method: endpoints.GetBillToInfo.method,
                    endpoint: `${endpoints.GetBillToInfo.url}?${params.toString()}`
                });

                const billToInfo = response.data;
                if (billToInfo != null) {
                    issConfig.billToAccountNumber = billToInfo.toString();
                    return Promise.resolve();
                }

                return Promise.reject(new Error('Invalid billToInfo'));
            } catch (e) {
                return Promise.reject(e);
            }
        },

        async validateClientTag(clientTag) {
            return await globalMethods.callHttpClient({
                method: endpoints.ValidateClientTag.method,
                endpoint: `${endpoints.ValidateClientTag.url}/${clientTag}`
            });
        },

        async validateClientSignature(clientTag, token, signature) {
            const payload = {
                clientTag,
                token,
                signature
            };

            return await globalMethods.callHttpClient({
                method: endpoints.ValidateClientSignature.method,
                endpoint: endpoints.ValidateClientSignature.url,
                payload
            });
        },

        saveServiceLocation(serviceLocationInfo) {
            this.updateServiceLocation(serviceLocationInfo);
        },

        saveRegistrationAddressLookup({ isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }) {
        // Reset dependent state when changing
            if
            (
                registrationInfo?.address !== this.order.vehicle.registration?.address
            || registrationInfo?.city !== this.order.vehicle.registration?.city
            || registrationInfo?.state !== this.order.vehicle.registration?.state
            || registrationInfo?.zipCode !== this.order.vehicle.registration?.zipCode
            || registrationInfo?.firstName !== this.order.vehicle.registration?.firstName
            || registrationInfo?.lastName !== this.order.vehicle.registration?.lastName
            ) {
                if (!isSelectedGlassAvailableForVehicle) {
                    this.resetDamageState();
                    this.resetGlassPartsState();
                }

                // Save new values
                this.updateRegistration(registrationInfo);
            }

            if (vehicleInfo) {
                this.updateVehicle(vehicleInfo);
            }
        },
        saveVin({ isSelectedGlassAvailableForVehicle, vehicleInfo }) {
        // Reset dependent state when changing
            if (vehicleInfo.vin !== this.order.vehicle.vin) {
                this.resetRegistrationAndDependencies();

                if (!isSelectedGlassAvailableForVehicle) {
                    this.resetDamageState();
                    this.resetGlassPartsState();
                }

                // Save new values
                this.updateVehicle(vehicleInfo);
            }
        },
        saveRegistrationLicensePlateLookup({ isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }) {
            // Reset dependent state when changing
            if (registrationInfo?.licensePlate !== this.order.vehicle.registration?.licensePlate
                || registrationInfo?.state !== this.order.vehicle.registration?.state) {
                this.resetRegistrationAndDependencies();

                if (!isSelectedGlassAvailableForVehicle) {
                    // Dependencies already cleared in above statement
                    this.resetDamageState();
                    this.resetGlassPartsState();
                }

                // Save new values
                this.updateVehicle(vehicleInfo);
            }

            this.updateRegistration(registrationInfo);
        },

        setBailout(bailoutData) {
            const params = new URL(document.location.toString()).searchParams;
            const currentPage = params.get('issPage');

            this.updatePageData({
                page: issPageValues.BAILOUT_PAGE,
                data: {
                    url: window.location.href,
                    page: currentPage || 'Unknown Page',
                    bailoutCode: bailoutData.code,
                    errorMessage: bailoutData.message,
                    submit: false
                }
            });
        },

        setBailoutContactInfo(contact) {
            this.order.customer.firstName = contact.firstName;
            this.order.customer.lastName = contact.lastName;
            this.order.customer.emailAddress = contact.email;
            this.updatePhoneNumbers({
                home: contact.phoneNumber,
                service: contact.phoneNumber
            });
            this.pageData(issPageValues.BAILOUT_PAGE).submit = true;
        },

        resetRegistrationAndDependencies() {
            this.resetRegistrationState();
            this.resetGlassPartsState();
            this.updateVaps(null);
        },

        resetDamageAndDependencies() {
            this.resetDamageState();
            this.resetGlassPartsState();
            this.updateVaps(null);
        },

        resetPartsAndDependencies() {
            this.resetGlassPartsState();
            this.updateVaps(null);

            this.resetServiceLocationAndDependencies();
        },

        resetServiceLocation() {
            this.order.serviceLocation.state = null;
            this.order.serviceLocation.zipCode = null;
            this.order.serviceLocation.zipCodeCtu = null;
            this.order.serviceLocation.defaultProviderNumber = null;
            this.order.serviceLocation.appointmentType = null;
            this.order.serviceLocation.IsSafeliteProvider = null;
            this.resetServiceLocationProvider();
            this.resetServiceLocationMobileAddress();
        },

        resetPageFields() {
            this.resetOrder();
            this.resetCustomer();
            this.resetPolicy();
            this.resetPayment();
            this.resetContactInfo();
            this.resetVehicleState();
            this.resetDamageState();
            this.resetGlassPartsState();
            this.resetInsurance();
            this.resetServiceLocation();
            this.resetSchedule();
            this.resetBailout();
            this.resetSubmittedOrder();
        },
        savePaymentMethodChoice(paymentMethod) {
            this.order.payment.paymentMethod = paymentMethod;
        },

        getPaymentSignature() {
            return globalMethods.callHttpClient({
                method: endpoints.GetPaymentSignature.method,
                endpoint: endpoints.GetPaymentSignature.url
            });
        },

        hasSubmittedOrder() {
            return window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER) !== null;
        },

        getSubmittedOrder() {
            return JSON.parse(window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER));
        },

        async createSubmittedOrder(submitType) {
            if (this.hasSubmittedOrder()) {
                return;
            }
            await this.getCarrierAccountInfo();
            const submittedOrder = this.order;
            const { experiments } = this.applicationUser;
            const { issConfig } = this;

            submittedOrder.isUnverified = this.isUnverified;
            submittedOrder.isVerified = this.isVerified;
            submittedOrder.submitType = submitType;
            submittedOrder.payment.isPayInAdvance = this.isPayInAdvance;

            // set to local storage
            window.sessionStorage.setItem(webStorageConstants.SUBMITTED_ORDER, JSON.stringify(submittedOrder));

            // clear vuex
            this.resetState();

            // delete cookie
            deleteISSCookie();

            // restore issConfig
            this.issConfig = issConfig;
            // restore user's experiments
            this.applicationUser.experiments = experiments;
        },

        resetSubmittedOrder() {
            // clear from local storage
            window.sessionStorage.removeItem(webStorageConstants.SUBMITTED_ORDER);
        }
    },
    persist: true
});

// Private Functions

function getHasRecalibrationPart(state) {
    const hasRequiresRecalibration = getNonFalseValuesOfPropertyInArrayOfObjects(state.order.lineItems.glassParts, 'requiresRecalibration')?.length > 0;
    const hasRecalibrationType = getNonFalseValuesOfPropertyInArrayOfObjects(state.order.lineItems.glassParts, 'recalibrationType')?.length > 0;

    if (hasRequiresRecalibration) {
        if (hasRecalibrationType) {
            // Has both 'requiresRecalibration' and 'recalibrationType' and 'recalibrationType'
            return (
                getNonFalseValuesOfPropertyInArrayOfObjects(
                    state.order.lineItems.glassParts,
                    'recalibrationType'
                )[0].toLowerCase() !== 'unknown'
            );
        }
        // Has 'requiresRecalibration' but no 'recalibrationType' at all
        return true;
    }
    // Does not have 'requiresRecalibration'
    return false;
}

function getNonFalseValuesOfPropertyInArrayOfObjects(array, propertyName) {
    return (array ?? []).map((x) => x[propertyName]).filter((x) => x);
}

function sortArrayOfObjectsByPropertyValue(arrayOfObjects, propertyName) {
    if (!arrayOfObjects) return null;

    return arrayOfObjects.sort((a, b) => {
        if (a[propertyName] < b[propertyName]) return -1;
        if (a[propertyName] > b[propertyName]) return 1;
        return 0;
    });
}

function convertGlassPieceNamingForApi(glassArray) {
    if (!glassArray || glassArray.length === 0) return [];

    // check if array already converted.  (likely when a session has been saved previously and then reloaded)
    if (glassArray[0].location !== undefined) {
        return glassArray;
    }

    const converted = [];
    glassArray.forEach((glass) => {
        converted.push({
            location: glass.glassLocation,
            name: glass.glassName
        });
    });
    return converted;
}

function convertResultsForApi(resultsArray) {
    if (!resultsArray) return [];
    const converted = [];
    resultsArray.forEach((answer) => {
        converted.push({
            location: answer.glassLocation,
            name: answer.glassName,
            result: answer.result
        });
    });
    return converted;
}

function convertGlassPieceNamingFromApi(glassArray) {
    glassArray.forEach((glass) => {
        glass.glassLocation = glass.glassPiece.location;
        glass.glassName = glass.glassPiece.name;
        delete glass.glassPiece;
        return glass;
    });
    return glassArray;
}

function addPricesToLineItems(lineItems, pricingLineItems) {
    const partOffset = {};

    lineItems.forEach((lineItem) => {
        if (lineItem.childParts) {
            addPricesToLineItems(lineItem.childParts, pricingLineItems);
        }
        const { partNumber } = lineItem;

        const pricedIndex = findLineItemIndex(pricingLineItems, partNumber, partOffset[partNumber] ?? 0);
        if (pricedIndex !== -1) {
            const pricedLineItem = pricingLineItems[pricedIndex];
            lineItem.laborAmount = pricedLineItem.laborAmount;
            lineItem.sellingPrice = pricedLineItem.sellingPrice;
            lineItem.kitPrice = pricedLineItem.kitPrice;
            partOffset[partNumber] = pricedIndex + 1;
        }
    });
    return lineItems;
}

function addTaxesToPricedLineItems(pricedLineItems, taxingLineItems = []) {
    pricedLineItems.forEach((pricedLineItem) => {
        const lineItemIndex = taxingLineItems.findIndex((taxingLineItem) => taxingLineItem.partNumber === pricedLineItem.partNumber);

        if (pricedLineItem.childParts) {
            addTaxesToPricedLineItems(pricedLineItem.childParts, taxingLineItems);
        }

        const taxedLineItem = taxingLineItems.splice(lineItemIndex, 1)[0];
        pricedLineItem.salesTax = taxedLineItem?.salesTax ?? 0;
    });

    return pricedLineItems;
}

function convertGlassPieceToBackEndCompatibleFormat(glassPieces) {
    return glassPieces.map((glassPiece) => ({
        location: glassPiece.glassLocation,
        name: glassPiece.glassName
    }));
}

function providersEqual(providerA, providerB) {
    return (
        providerA.providerNumber === providerB.providerNumber
        && providerA.address?.city === providerB.address?.city
        && providerA.address?.state === providerB.address?.state
        && providerA.address?.streetAddress === providerB.address?.streetAddress
        && providerA.address?.zipCode === providerB.address?.zipCode
    );
    // TODO: Change back to deepEqual once zipCodeCtu is added to saveSession.
}

function provisionalTriggersToString(provisionalTriggers) {
    return `ProvisionalTriggers:${provisionalTriggers.join(',')}`;
}

function setClearOnSubmit(lineItemArray, shouldClearOnSubmit) {
    const retArray = [];
    if (lineItemArray && lineItemArray.length > 0) {
        lineItemArray.forEach((part) => {
            const newPart = { ...part };
            newPart.clearOnSubmit = shouldClearOnSubmit;

            retArray.push(newPart);
        });
    }

    return retArray;
}
