import { logger } from '@sentry/react';
import { DEFAULT_BREADCRUMB_LEVEL } from './breadcrumb';
import { fillTyped } from './utils/fill';
import { convertToNormalizedObject } from './utils/normalize';
import { NATIVE } from './wrapper';
/**
 * This WeakMap is used to keep track of which scopes have been synced to the native SDKs.
 * This ensures that we don't double sync the same scope.
 */
const syncedToNativeMap = new WeakMap();
/**
 * Hooks into the scope set methods and sync new data added to the given scope with the native SDKs.
 */
export function enableSyncToNative(scope) {
    if (syncedToNativeMap.has(scope)) {
        return;
    }
    syncedToNativeMap.set(scope, true);
    fillTyped(scope, 'setUser', original => (user) => {
        NATIVE.setUser(user);
        return original.call(scope, user);
    });
    fillTyped(scope, 'setTag', original => (key, value) => {
        NATIVE.setTag(key, NATIVE.primitiveProcessor(value));
        return original.call(scope, key, value);
    });
    fillTyped(scope, 'setTags', original => (tags) => {
        // As native only has setTag, we just loop through each tag key.
        Object.keys(tags).forEach(key => {
            NATIVE.setTag(key, NATIVE.primitiveProcessor(tags[key]));
        });
        return original.call(scope, tags);
    });
    fillTyped(scope, 'setExtras', original => (extras) => {
        Object.keys(extras).forEach(key => {
            NATIVE.setExtra(key, extras[key]);
        });
        return original.call(scope, extras);
    });
    fillTyped(scope, 'setExtra', original => (key, value) => {
        NATIVE.setExtra(key, value);
        return original.call(scope, key, value);
    });
    fillTyped(scope, 'addBreadcrumb', original => (breadcrumb, maxBreadcrumbs) => {
        const mergedBreadcrumb = Object.assign(Object.assign({}, breadcrumb), { level: breadcrumb.level || DEFAULT_BREADCRUMB_LEVEL, data: breadcrumb.data ? convertToNormalizedObject(breadcrumb.data) : undefined });
        original.call(scope, mergedBreadcrumb, maxBreadcrumbs);
        const finalBreadcrumb = scope.getLastBreadcrumb();
        if (finalBreadcrumb) {
            NATIVE.addBreadcrumb(finalBreadcrumb);
        }
        else {
            logger.warn('[ScopeSync] Last created breadcrumb is undefined. Skipping sync to native.');
        }
        return scope;
    });
    fillTyped(scope, 'clearBreadcrumbs', original => () => {
        NATIVE.clearBreadcrumbs();
        return original.call(scope);
    });
    // oxlint-disable-next-line typescript-eslint(no-explicit-any)
    fillTyped(scope, 'setContext', original => (key, context) => {
        NATIVE.setContext(key, context);
        return original.call(scope, key, context);
    });
    fillTyped(scope, 'setAttribute', original => (key, value) => {
        // Only sync primitive types
        if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
            NATIVE.setAttribute(key, value);
        }
        return original.call(scope, key, value);
    });
    fillTyped(scope, 'setAttributes', original => (attributes) => {
        // Filter to only primitive types
        const primitiveAttrs = {};
        Object.keys(attributes).forEach(key => {
            const value = attributes[key];
            if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
                primitiveAttrs[key] = value;
            }
        });
        if (Object.keys(primitiveAttrs).length > 0) {
            NATIVE.setAttributes(primitiveAttrs);
        }
        return original.call(scope, attributes);
    });
    fillTyped(scope, 'removeAttribute', original => (key) => {
        NATIVE.removeAttribute(key);
        return original.call(scope, key);
    });
}
//# sourceMappingURL=scopeSync.js.map