import { EventEmitter } from 'events';
import { QueryCache } from 'react-query/core';
import { createMemoryHistory } from 'history';
import { testkit, } from '@wix/fe-essentials-standalone/testkit';
import { Trans, useExperiments, useTranslation, } from '@wix/fe-essentials-standalone/react';
import { whenRequest } from '@wix/fe-essentials/http-client/testkit/client';
import { AppSettingsStorageStrategy, DataCapsule, } from '@wix/fe-essentials/data-capsule';
import { WixPatternsContainer } from '../state';
import { partialLodashMock } from '../mocks/partialLodashMock';
import { debounce, throttle } from 'lodash';
import { exportServiceMocks } from './exportServiceMocks';
import { NavigationManager } from '../services/navigationManager';
import { matchMediaMock } from './matchMediaMock';
import { isJestExists, isTestEnvironment } from '../test-utils/jest';
import { appSettingsMocks } from './appSettingsMocks';
import { ErrorHandler } from '@wix/fe-essentials/error-handler';
export class WixPatternsContainerDriver {
    get tableDataCapsule() {
        return this.dataCapsuleInstances.get('cairo.cairo-test-component.wix.cairo.products.v1.product');
    }
    constructor(overrides = {
        asMobileView: false,
        contextType: 'SITE',
    }) {
        this.onlineManager = {
            _events: new EventEmitter(),
            _isOnline: true,
            setIsOnline(value) {
                this._isOnline = value;
                this._events.emit('default');
            },
            isOnline() {
                return this._isOnline;
            },
            subscribe(listener) {
                if (listener) {
                    this._events.on('default', listener);
                }
                return () => {
                    if (listener) {
                        this._events.removeListener('default', listener);
                    }
                };
            },
        };
        this.focusManager = {
            _events: new EventEmitter(),
            _isFocused: true,
            setIsFocused(value) {
                this._isFocused = value;
                this._events.emit('default');
            },
            isFocused() {
                return this._isFocused;
            },
            subscribe(listener) {
                if (listener) {
                    this._events.on('default', listener);
                }
                return () => {
                    if (listener) {
                        this._events.removeListener('default', listener);
                    }
                };
            },
        };
        this.queryCache = new QueryCache();
        this.patchesCache = new Map();
        this.dataCapsule = [];
        this.dataCapsuleInstances = new Map();
        this.componentSettingsInstances = new Map();
        this.exportServiceMocks = exportServiceMocks(whenRequest);
        this.testContext = testkit.getTestContext({
            experiments: {
                bag: overrides.experiments,
            },
            environment: {
                language: 'en',
                ...overrides?.environment,
            },
            i18n: {
                messages: (language) => require(`../assets/locale/messages_${language}.json`),
            },
            errorMonitor: {},
            httpClient: {
                scenarios: [
                    /* metro-testkit currently takes the first mock it encounters per API,
                    so overrides must be added before appSettingsMocks(whenRequest) */
                    ...(overrides.appSettingsCustomMocks ?? []),
                    ...appSettingsMocks(whenRequest),
                    ...this.exportServiceMocks.mocks,
                    ...(overrides.httpMocks ?? []),
                ],
            },
        });
        this.testContext.essentials._parent.environment.artifactId =
            'cairo';
        const { asyncExperiments } = overrides;
        if (asyncExperiments) {
            this.testContext.experiments.ready = async () => {
                await asyncExperiments();
            };
        }
        this.window = {
            location: {
                href: 'https://cairo.test',
                ...overrides.location,
            },
            download: jest.fn(),
            matchMedia: jest.fn().mockImplementation((query) => ({
                ...matchMediaMock(query),
                matches: !overrides.asMobileView,
            })),
            close: () => {
                window.dispatchEvent(new Event('beforeunload'));
                window.dispatchEvent(new Event('unload'));
            },
        };
        this.navigationManager = new NavigationManager(this.window);
        this.showToast =
            overrides?.showToast ??
                jest.fn().mockImplementation(() => ({ remove: () => { } }));
        this.usePageLocation = overrides.usePageLocation ?? jest.fn();
        this.navigateTo = overrides?.navigateTo ?? jest.fn();
        this.onLayerStateChange =
            overrides?.onLayerStateChange ??
                jest.fn().mockReturnValue({ remove: () => { } });
        this.onNavigation =
            overrides?.onNavigation ??
                jest
                    .fn()
                    .mockImplementation((callback) => {
                    const remove = this.navigationManager.subscribe((state) => {
                        state.prevented = true;
                        callback(state.pause);
                    });
                    return {
                        remove,
                    };
                });
        if (!overrides.onBeforeUnloadMissingInEnvironment) {
            this.onBeforeUnload =
                overrides?.onBeforeUnload ??
                    jest.fn().mockImplementation((callback) => {
                        const remove = this.navigationManager.subscribe((state) => {
                            const { resume } = state.pause();
                            callback({
                                preventDefault: () => {
                                    state.prevented = true;
                                    this.navigationManager.events.once('navigationPromptResult', (leave) => {
                                        if (leave) {
                                            resume();
                                        }
                                    });
                                },
                            });
                        });
                        return {
                            remove,
                        };
                    });
        }
        this.history = overrides.historyInstance || createMemoryHistory();
        if (overrides?.history?.search) {
            this.replaceHistory(overrides.history.search);
        }
        this.container = new WixPatternsContainer({
            queryCache: this.queryCache,
            patchesCache: this.patchesCache,
            errorMonitor: this.testContext.errorMonitor,
            errorHandler: !overrides.noErrorHandler
                ? new ErrorHandler({
                    biLoggerOrFactory: this.testContext.asPartial.biLogger ??
                        this.testContext.biLoggerFactory,
                    createErrorMonitor: (options) => this.testContext.createChildEssentials({ errorMonitor: options })
                        .errorMonitor,
                    environment: this.testContext.environment,
                    createI18n: (options) => this.testContext.createChildEssentials({ i18n: options }).i18n,
                }).v2
                : undefined,
            history: this.history,
            contextType: overrides.contextType,
            environment: {
                ...this.testContext.environment,
                ...overrides?.environment,
                componentId: [
                    this.testContext.environment.artifactId,
                    'cairo-test-component',
                ].join('.'),
                providerType: 'bm',
            },
            environmentBI: {
                artifactId: this.testContext.environment.artifactId,
            },
            user: {
                permissions: [],
                ...overrides?.user,
            },
            httpClient: this.testContext.httpClient,
            experiments: this.testContext.experiments,
            onlineManager: this.onlineManager,
            focusManager: this.focusManager,
            window: this.window,
            useTranslation,
            Trans,
            useExperiments,
            createComponentSettings: overrides.componentSettingsLocalStorage
                ? undefined
                : () => ({ namespace }) => {
                    const componentSettings = new DataCapsule({
                        namespace,
                        scope: '',
                        strategy: new AppSettingsStorageStrategy({
                            host: 'other',
                            httpClient: this.testContext.httpClient,
                        }),
                    });
                    const data = overrides.componentSettingsEntries?.[namespace];
                    if (data) {
                        for (const [key, value] of Object.entries(data)) {
                            componentSettings.setItem(key, value);
                        }
                    }
                    this.componentSettingsInstances.set(namespace, componentSettings);
                    return componentSettings;
                },
            messagesEnImport: overrides.i18nOverrides?.messagesEnImport,
            fetchTranslations: overrides.i18nOverrides?.fetchTranslations,
            createEssentials: (options) => {
                const i18nOptions = options.i18n;
                const childEssentials = this.testContext.createChildEssentials({
                    ...options,
                    ...(i18nOptions && {
                        i18n: {
                            ...i18nOptions,
                            asyncMessagesLoader: (locale) => Promise.all([
                                i18nOptions.asyncMessagesLoader?.(locale) ?? {},
                                overrides.i18nOverrides?.asyncMessagesLoader?.(locale) ?? {},
                            ]).then((messages) => messages.reduce(Object.assign, {})),
                        },
                    }),
                    ...(options.experiments && {
                        experiments: {
                            bag: {
                                'specs.os.EnableErrorHandlerInEditor': 'true',
                                ...('bag' in options.experiments
                                    ? options.experiments.bag
                                    : undefined),
                                ...overrides.internalExperiments,
                            },
                        },
                    }),
                });
                if (options.dataCapsule && childEssentials.dataCapsule) {
                    this.dataCapsule.push(childEssentials.dataCapsule);
                    this.dataCapsuleInstances.set(options.dataCapsule.namespace, childEssentials.dataCapsule);
                    for (const [key, value] of Object.entries(overrides.dataCapsule?.entries ?? {})) {
                        childEssentials.dataCapsule.setItem(key, value);
                    }
                }
                return childEssentials;
            },
            showToast: this.showToast,
            usePageLocation: this.usePageLocation,
            navigateTo: (to) => {
                this.navigateTo?.(to);
                this.navigationManager.navigateToPage(to);
            },
            onNavigation: this.onNavigation,
            onBeforeUnload: this.onBeforeUnload,
            onLayerStateChange: this.onLayerStateChange,
            openMediaManager: overrides?.openMediaManager,
            getHostContainer: overrides?.getHostContainer,
            lodash: isTestEnvironment() && isJestExists() && jest.isMockFunction(setTimeout)
                ? partialLodashMock()
                : { debounce, throttle },
        });
        this.container.init();
    }
    get errorMonitor() {
        return this.testContext.errorMonitor;
    }
    get errorHandler() {
        return this.container.errorHandler;
    }
    get i18n() {
        return this.container.i18n;
    }
    get onlineState() {
        return this.container.onlineState;
    }
    get environment() {
        return this.container.environment;
    }
    get environmentBI() {
        return this.container.environmentBI;
    }
    get getHostContainer() {
        return this.container.getHostContainer;
    }
    get biLoggerFactory() {
        return this.testContext.biLoggerFactory;
    }
    replaceHistory(searchParams) {
        const search = searchParams.toString();
        this.history.replace({
            ...this.history.location,
            search: search ? `?${search}` : '',
        });
    }
}
//# sourceMappingURL=WixPatternsContainer.driver.js.map