<template>
    <p
    v-show="unauthorized"
    id="message">
    Unauthorized Access.
    </p>
</template>

<script>
// Supporting files
import issPageValues from '@/router/router-constants/issPage-values';
import { validateISSClientTag, validateISSClientSignature } from '@/helpers/clientauth-helper';
import { getISSCookie, updateOrCreateISSCookie } from '@/helpers/cookie-helper.js';
import { useMainStore } from '@/store';
import showIssLoadingModal from '@/helpers/loading-modal-helper';
import { toPossessive } from '@/helpers/text-helper';
import analyticsMixin from '@/mixins/analytics-mixin';
import routerParams from '@/router/router-constants/router-params';

export default {
    name: 'entry-page',
    components: {
    },
    mixins: [],
    setup() {
        const mainStore = useMainStore();
        mainStore.populateInitialState(true);
        return { mainStore };
    },
    data() {
        return {
            unauthorized: false
        };
    },
    computed: {
    },
    async mounted() {
        try {
            const queryStringParams = this.parseQueryParms();
            const { isAuthorized, clientData, decryptedParams } = await this.validateClientTagOnEntry(queryStringParams);

            this.unauthorized = !isAuthorized;
            if (!isAuthorized) {
                // Remove the loading animation if client tag validation fails so users can see the Unauthorized Access message.
                showIssLoadingModal(false);
                return;
            }
            
            try {
                // Check cookie
                const issCookie = getISSCookie();
                if (issCookie !== null && issCookie.VehicleMake && issCookie.VehicleModel) {
                    const clientParentAccountNumber = clientData.parentAccountNumber;
                    const cookieParentAccountNumber = issCookie.ReferralParentAccountNumber;

                    if (clientParentAccountNumber === cookieParentAccountNumber) {
                        const savedSessionTimeStamp = new Date(issCookie.SavedSessionTimeoutDate);
                        const isSavedSessionTimedOut = new Date(new Date().toUTCString()) > savedSessionTimeStamp;

                        if (!isSavedSessionTimedOut) {
                            this.mainStore.issConfig.enableContinueFromCookie = true;
                        }
                    }
                } else {
                    updateOrCreateISSCookie(true);
                }
            } catch {
                updateOrCreateISSCookie(true);
            }

            if (clientData.parameters?.length > 0) {
                const finalParams = this.combineClientParameters(clientData.parameters, { ...queryStringParams, ...decryptedParams });
                this.populateStoreItemsFromParams(finalParams);
            }
        } catch (e) {
            global.$logger.logError('[Entry Page] Client Setup Error:', e);
            this.unauthorized = true;
            showIssLoadingModal(false);
            return;
        }

        this.mainStore.applicationUser.coverageAttempts = 0;

        // Forced full location redirect here. We do not want the entry page as part of the router/flow/path history.
        window.location = `/?issPage=${issPageValues.WELCOME_PAGE}`;
    },
    methods:
        {
            navigateForward() {
                // If we use navigateForward we need to skip saving session (creating referral).
                this.$router.navigate(
                    this.navigationScenarios.MOVE_FORWARD_ENTRY_PAGE,
                    this.$route,
                    {},
                    { [routerParams.SKIP_SAVE_SESSION]: true }
                );
            },
            parseQueryParms() {
                // Dump the query string parameters into an object
                if (this.$route?.query) {
                    return Object.fromEntries(Object.entries(this.$route?.query).map(([key, value]) => [key.toLowerCase(), value]));
                }

                return {};
            },
            async validateClientTagOnEntry(queryStringParams) {
                const clientTag = queryStringParams.clienttag;
                if (!clientTag) {
                    return { isAuthorized: false };
                }

                // Set the client tag on the store here so we can use it for logging if need be.
                this.mainStore.issConfig.clientTag = clientTag;

                const resp = await validateISSClientTag(clientTag);
                if (!resp) {
                    return { isAuthorized: false };
                }

                // Populate all the ISS Config values from the service call returns.
                this.populateISSConfigValues(resp);

                // Session should only be created / validated on successful client tag validation to avoid unnecessary sessions for unauthorized users.
                await analyticsMixin.methods.validateSession();

                let isAuthorized = false;
                let clientData = null;
                const decryptedParams = {};
                const encryptedParametersPattern = this.mainStore.issConfig.encryptedParametersPattern;

                if (resp.active && resp.accountName.length > 0) {
                    if (resp.authentication.startsWith('RSAToken')) {
                        const { token, signature } = queryStringParams;
                        const vsigResp = await validateISSClientSignature(clientTag, token, signature);
                                                
                        // Encrypted params only populated if the authentication type includes EncParams and we have a pattern to pull them out of the decrypted data.
                        // Try/Catch is here to ensure that any issues with populating these parameters does not impact the overall authentication/authorization of the client.
                        // They can fallback to manually entering the data on the webpage.
                        if (resp.authentication.includes('EncParams') && encryptedParametersPattern) {
                            try {
                                const encryptedParametersPatternRegex = RegExp(encryptedParametersPattern);
                                const match = vsigResp.decryptedData.match(encryptedParametersPatternRegex);

                                if ( match?.groups ) {
                                    const params = match.groups;
                                    for (const [key, value] of Object.entries(params)) {
                                        decryptedParams[key.toLowerCase()] = value;
                                    }
                                }
                            }
                            catch ( error ) {
                                global.$logger.logError(`[Entry Page] Unable to populate encrypted parameters: ${error} - Client Tag: ${clientTag} - Token: ${token} - Signature: ${signature}`);
                            }
                        }

                        isAuthorized = vsigResp?.valid ?? false;
                        this.mainStore.issConfig.isAuthenticated = isAuthorized;

                        // Log the signature validation failure so we can monitor/alert on it.
                        if ( !isAuthorized ) {
                            global.$logger.logError(`[Entry Page] Client signature validation failed for Client Tag: ${clientTag} - Reason: ${vsigResp?.failureReason ?? ''} - Token: ${token} - Signature: ${signature}`);
                        }
                    } else {
                        isAuthorized = true;
                    }

                    if (isAuthorized) {                         
                        clientData = resp;
                    }
                }

                return { isAuthorized, clientData, decryptedParams };
            },
            populateISSConfigValues(data) {
                this.mainStore.issConfig.clientName = data.accountName;
                this.mainStore.issConfig.clientFullName = data.accountName; // Defaults to use the client name.
                this.mainStore.issConfig.clientDisplayName = data.accountName; // Defaults to use the client name.
                this.mainStore.issConfig.clientPossessiveName = toPossessive(data.accountName); // Defaults to use the client name.
                this.mainStore.issConfig.parentAccountNumber = data.parentAccountNumber;
                this.mainStore.issConfig.styleSheet = data.styleSheet;
                this.mainStore.issConfig.isCoverageEnabled = data.coverageEnabled;
                this.mainStore.issConfig.siteType = data.siteType;

                if (data.clientFlags) {
                    const clientFlags = JSON.parse(data.clientFlags);

                    if (clientFlags.TPAEnabled) {
                        this.mainStore.issConfig.enableTPAFlow = true;
                    }

                    if (clientFlags.ClientFullName != null) {
                        this.mainStore.issConfig.clientFullName = clientFlags.ClientFullName;
                    }

                    if (clientFlags.ClientDisplayName != null) {
                        this.mainStore.issConfig.clientDisplayName = clientFlags.ClientDisplayName;
                        this.mainStore.issConfig.clientPossessiveName = toPossessive(clientFlags.ClientDisplayName);
                    }

                    if (clientFlags.ClientPossessiveName != null) {
                        this.mainStore.issConfig.clientPossessiveName = clientFlags.ClientPossessiveName;
                    }

                    if (clientFlags.ClaimRegistrationRequired) {
                        this.mainStore.issConfig.isClaimRegistrationRequired = true;
                    }

                    if (clientFlags.EnableNoCompQuote) {
                        this.mainStore.issConfig.enableNoCompQuote = true;
                    }

                    if ( clientFlags.EncryptedParametersPattern != null ) {
                        this.mainStore.issConfig.encryptedParametersPattern = clientFlags.EncryptedParametersPattern;
                    }

                    if (clientFlags.UseMemberNumber) {
                        this.mainStore.issConfig.useMemberNumber = true;
                    }

                    if (clientFlags.HiddenFields) {
                        if (clientFlags.HiddenFields.includes('PolicyNumber')) {
                            this.mainStore.issConfig.hiddenFields.policyNumber = true;
                        }

                        if (clientFlags.HiddenFields.includes('PhoneNumber')) {
                            this.mainStore.issConfig.hiddenFields.phoneNumber = true;
                        }
                    }
                }
            },
            combineClientParameters(configParams, queryStringParams) {
                const finalParams = {};

                try {
                    const clientParams = JSON.parse(configParams);
                    for (const clientParam of clientParams) {
                        const paramName = clientParam.toLowerCase();
                        const value = queryStringParams[paramName];
                        if (value) {
                            finalParams[paramName] = value;
                        }
                    }
                } catch (e) {
                    window.console.error(`Error combining client parameters: ${e}`);
                }

                return finalParams;
            },
            populateStoreItemsFromParams(params) {
                // Populate store items from parameters.
                for (const [key, value] of Object.entries(params)) {
                    switch (key.toLowerCase()) {
                        case 'policynbr':
                        case 'policynumber':
                            this.mainStore.order.policy.policyNumber = value;
                            this.mainStore.issConfig.disabledFields.policyNumber = true;
                            break;

                        case 'policyzipcode':
                            this.mainStore.order.policy.policyZipCode = value;
                            this.mainStore.issConfig.disabledFields.policyZipCode = true;
                            break;

                        case 'dateofloss':
                        case 'lossdate':                            
                            const formattedDate = this.formatToYYYYMMDD(value);

                            // Only set this if it formatted correctly.
                            if ( formattedDate ) {
                                this.mainStore.order.policy.dateOfLoss = formattedDate;
                                this.mainStore.issConfig.disabledFields.dateOfLoss = true;
                            }
                            break;

                        case 'returnurl':
                        case 'successreturnurl':
                            this.mainStore.issConfig.successReturnURL = value;
                            break;

                        case 'returnurl2':
                        case 'failurereturnurl':
                            this.mainStore.issConfig.failureReturnURL = value;
                            break;

                        // Not stored
                        case 'timestamp':
                        case 'token':
                        case 'signature':
                            break;
                        default:
                    }
                }
            },            
            formatToYYYYMMDD(dateString) {
                try {
                    if (!dateString) {
                        return null;
                    }

                    // Avoid any UTC / local time issues by always treating the output as UTC.
                    const date = new Date(dateString);
                    if (Number.isNaN(date.getTime())) {
                        return null;
                    }

                    const year = date.getUTCFullYear();
                    const month = String(date.getUTCMonth() + 1).padStart(2, "0");
                    const day = String(date.getUTCDate()).padStart(2, "0");

                    return `${year}-${month}-${day}`;
                } catch ( error ) {
                    global.$logger.logError(`[Entry Page] Error formatting date string: ${error} - Input: ${dateString}`);
                    return null;
                }
            }
        }
    };
</script>

<style lang="scss" scoped>
#message {
    text-align: center;
}
</style>
