import { isNothing, isSome } from "@jet/environment";
import * as validation from "@jet/environment/json/validation";
import { makeMetatype } from "@jet/environment/util/metatype";
/**
 * @public
 * Type to define which type of metrics identifier key to use to fetch identifiers, fields, etc.
 */
export var MetricsIdentifierType;
(function (MetricsIdentifierType) {
    MetricsIdentifierType["client"] = "clientId";
    MetricsIdentifierType["user"] = "userId";
    MetricsIdentifierType["canonical"] = "canonicalAccountIdentifierOverride";
})(MetricsIdentifierType || (MetricsIdentifierType = {}));
/**
 * @public
 * The default namespaces to provide to the native `MetricsIdStore` for fetching and caching
 */
export var MetricsIdentifiersDefaultBagNamespaces;
(function (MetricsIdentifiersDefaultBagNamespaces) {
    MetricsIdentifiersDefaultBagNamespaces["client"] = "APPSTORE_ENGAGEMENT_CLIENT";
    MetricsIdentifiersDefaultBagNamespaces["user"] = "APPSTORE_ENGAGEMENT";
})(MetricsIdentifiersDefaultBagNamespaces || (MetricsIdentifiersDefaultBagNamespaces = {}));
export var MetricsIdentifiersPaymentBagNamespaces;
(function (MetricsIdentifiersPaymentBagNamespaces) {
    MetricsIdentifiersPaymentBagNamespaces["client"] = "APPSTORE_PAYMENTS_ENGAGEMENT_CLIENT";
    MetricsIdentifiersPaymentBagNamespaces["user"] = "APPSTORE_PAYMENTS_ENGAGEMENT";
})(MetricsIdentifiersPaymentBagNamespaces || (MetricsIdentifiersPaymentBagNamespaces = {}));
export var MetricsIdentifiersPersonalizationBagNamespaces;
(function (MetricsIdentifiersPersonalizationBagNamespaces) {
    MetricsIdentifiersPersonalizationBagNamespaces["user"] = "APPSTORE_PERSONALIZATION";
})(MetricsIdentifiersPersonalizationBagNamespaces || (MetricsIdentifiersPersonalizationBagNamespaces = {}));
/**
 * The payment context mappings for a metrics identifier key.
 */
export const paymentIdentifierContextMapping = {
    [MetricsIdentifierType.client]: {
        keyType: MetricsIdentifierType.client,
        bagNamespace: MetricsIdentifiersPaymentBagNamespaces.client,
        crossSyncDevice: false,
    },
    [MetricsIdentifierType.user]: {
        keyType: MetricsIdentifierType.user,
        bagNamespace: MetricsIdentifiersPaymentBagNamespaces.user,
        crossSyncDevice: true,
    },
};
/**
 * The default context mappings for a metrics identifier key.
 */
const defaultIdentifierContextMapping = {
    [MetricsIdentifierType.client]: {
        keyType: MetricsIdentifierType.client,
        bagNamespace: MetricsIdentifiersDefaultBagNamespaces.client,
        crossSyncDevice: false,
    },
    [MetricsIdentifierType.user]: {
        keyType: MetricsIdentifierType.user,
        bagNamespace: MetricsIdentifiersDefaultBagNamespaces.user,
        crossSyncDevice: true,
    },
};
/**
 * The personalization context mappings for a metrics identifier key.
 */
export const personalizationIdentifierContextMapping = {
    [MetricsIdentifierType.user]: {
        keyType: MetricsIdentifierType.user,
        bagNamespace: MetricsIdentifiersPersonalizationBagNamespaces.user,
        crossSyncDevice: true,
    },
};
/**
 * Represents a cache for metrics identifiers and fields.
 */
export class MetricsIdentifiersCache {
    /**
     * Constructs a new instance of the MetricsIdentifiersCache class.
     * @param identifierContextMapping - The mapping of identifier types to key contexts.
     */
    constructor(identifierContextMapping = defaultIdentifierContextMapping) {
        this.cachedMetricsIds = {};
        this.cachedMetricsFields = {};
        /**
         * A flag indicating whether a DSID fallback field should be added to the event fields.
         */
        this.shouldAddDsIdFallbackField = false;
        /**
         * The DSID of the currently logged in user on this JS request.
         */
        this.userDsId = null;
        this.identifierContextMapping = identifierContextMapping;
    }
    /**
     * Loads the values for the specified identifier types.
     * @param objectGraph - The object graph.
     * @param idTypes - The identifier types.
     * @returns A promise that resolves to an array of loaded values.
     */
    async loadValues(objectGraph, idTypes) {
        if (objectGraph.bag.isMetricsUserIdFallbackEnabled && !objectGraph.user.isUnderThirteen) {
            this.shouldAddDsIdFallbackField = true;
            this.userDsId = objectGraph.user.dsid;
        }
        else {
            this.shouldAddDsIdFallbackField = false;
            this.userDsId = null;
        }
        const loadedValues = [];
        for (const idType of idTypes) {
            const idTypeLoadedValues = await this.loadValuesForIdType(objectGraph, idType);
            loadedValues.push(idTypeLoadedValues);
        }
        for (const { idType, id, fields } of loadedValues) {
            if (id) {
                this.cachedMetricsIds[idType] = id;
            }
            if (fields) {
                this.cachedMetricsFields[idType] = fields;
            }
        }
    }
    /**
     * @param objectGraph The app store object graph for all our native dependencies
     * @param idType The type of id we're loading values for
     * @returns The MetricsIdStore values for this id type
     */
    async loadValuesForIdType(objectGraph, idType) {
        const returnValues = {
            idType,
        };
        const context = this.identifierContextMapping[idType];
        if (context) {
            try {
                const fields = await validation.context("MetricsIdentifiersCache:loadValues:metricsFields", async () => {
                    return await objectGraph.metricsIdentifiers.getMetricsFieldsForContexts([context]);
                });
                if (isSome(fields)) {
                    returnValues["fields"] = fields;
                    const extractedIdValue = fields[idType];
                    if (isSome(extractedIdValue) &&
                        typeof extractedIdValue === "string" &&
                        extractedIdValue.length > 0) {
                        returnValues["id"] = extractedIdValue;
                    }
                }
            }
            catch (error) {
                objectGraph.console.error(`Unable to fetch metrics fields for idType ${idType}`, error);
            }
            if (isNothing(returnValues["id"])) {
                try {
                    const id = await validation.context("MetricsIdentifiersCache:loadValues:metricsIdentifier", async () => {
                        return await objectGraph.metricsIdentifiers.getIdentifierForContext(context);
                    });
                    if (isSome(id)) {
                        returnValues["id"] = id;
                    }
                }
                catch (error) {
                    objectGraph.console.error(`Unable to fetch metrics identifier for idType ${idType}`, error);
                }
            }
        }
        return returnValues;
    }
    /**
     * Gets the metrics identifier for the specified identifier type.
     * @param idType - The identifier type.
     * @returns The metrics identifier, or undefined if not found.
     */
    getMetricsIdForType(idType) {
        return this.cachedMetricsIds[idType];
    }
    /**
     * Gets the metrics fields for the specified identifier types.
     * @param idTypes - The identifier types.
     * @returns The metrics fields, or undefined if not found.
     */
    getMetricsFieldsForTypes(idTypes) {
        const fieldsForTypes = idTypes.map((idType) => { var _a; return (_a = this.cachedMetricsFields[idType]) !== null && _a !== void 0 ? _a : {}; });
        const eventFields = Object.assign({}, ...fieldsForTypes);
        if (this.shouldAddDsIdFallbackField && idTypes.indexOf(MetricsIdentifierType.user) !== -1) {
            this.addDsIdFallbackFieldIfNecessary(eventFields);
        }
        return eventFields;
    }
    /**
     * Adds a DSID fallback field to the event fields if necessary.
     * @param eventFields - The event fields.
     */
    addDsIdFallbackFieldIfNecessary(eventFields) {
        const existingUserId = eventFields[MetricsIdentifierType.user];
        const isExistingUserIdInvalid = isNothing(existingUserId) ||
            typeof existingUserId !== "string" ||
            existingUserId.length === 0 ||
            existingUserId.length === MetricsIdentifiersCache.clientGeneratedUserIdLength;
        if (isExistingUserIdInvalid && isSome(this.userDsId) && this.userDsId.length > 0) {
            eventFields["dsId"] = this.userDsId;
        }
    }
    /**
     * Allows the setting of an app-level canonical account override for downstream metrics computations
     * @param canonicalAccountIdentifier - The identifier to use when operated with canonical account overides
     */
    setCanonicalAccountIdentifierOverride(canonicalAccountIdentifier) {
        if (canonicalAccountIdentifier.length >= 0) {
            this.cachedMetricsFields[MetricsIdentifierType.canonical] = {
                [MetricsIdentifierType.canonical]: canonicalAccountIdentifier,
            };
        }
    }
}
/**
 * The metatype of the MetricsIdentifiersCache class.
 */
MetricsIdentifiersCache.defaultMetatype = makeMetatype("app-store:metricsIdentifiersCache");
MetricsIdentifiersCache.paymentMetatype = makeMetatype("app-store:paymentMetricsIdentifiersCache");
MetricsIdentifiersCache.personalizationMetatype = makeMetatype("app-store:personalizationMetricsIdentifiersCache");
/**
 * The length of a client generated user ID.
 */
MetricsIdentifiersCache.clientGeneratedUserIdLength = 24;
export class MockMetricsIdentifiersCache extends MetricsIdentifiersCache {
    constructor() {
        super();
        this.cachedMetricsIds = {
            [MetricsIdentifierType.client]: "1a2b3c4d5e",
            [MetricsIdentifierType.user]: "1a2b3c4d5e",
        };
        this.cachedMetricsFields = {
            [MetricsIdentifierType.client]: {
                clientId: "1a2b3c4d5e",
            },
            [MetricsIdentifierType.user]: {
                userNs: "mockuserNs",
                userId: "1a2b3c4d5e",
                metricsId: 2,
            },
            [MetricsIdentifierType.canonical]: {
                canonicalAccountIdentifierOverride: "mockCanonicalAccountIdentifier",
            },
        };
    }
}
//# sourceMappingURL=metrics-identifiers-cache.js.map