var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
    return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
    if (kind === "m") throw new TypeError("Private method is not writable");
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
    return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var _WebDispatcher_requestBuilder, _WebDispatcher_timers, _WebDispatcher_dispatcher, _WebDispatcher_dispatcherUnsubscribe, _WebDispatcher_remoteRuntime, _WebDispatcher_localRuntime, _WebDispatcher_pauseSnapshot;
import { JsDispatcherImpl, TimerDefinition } from '@devvit/multiplatform/ui-shared-shared.js';
import { Header } from '@devvit/shared-types/Header.js';
import { initDevvitGlobal } from '../../types/devvit-global.js';
import { LocalRuntime, RemoteRuntime, RenderPostContent, UIRequestBuilder } from './runtimes.js';
import { Timers } from './timers.js';
const isCircuitBreakError = (e) => e.message === 'ServerCallRequired';
class Logger {
    debug(messages) {
        if (devvit?.debug.runtime)
            console.debug(this.tag(), ...messages);
    }
    error(messages) {
        if (isCircuitBreakError(messages[0]))
            return;
        console.error(this.tag(), ...messages);
    }
    info(messages) {
        console.info(this.tag(), ...messages);
    }
    warn(messages) {
        console.warn(this.tag(), ...messages);
    }
    tag() {
        return '[kmp-dispatcher]';
    }
}
class UIPerformanceAnalyticsDelegate {
    constructor() {
        // @ts-expect-error No clue
        this.__doNotUseOrImplementIt = {
            'net.devvit.analytics.PerformanceAnalyticsDelegate': Symbol('net.devvit.analytics.PerformanceAnalyticsDelegate'),
        };
    }
    logRuntimeError(errorInfo) {
        if (isCircuitBreakError(errorInfo))
            return;
        console.error('[kmp-dispatcher-perf-analytics] error', errorInfo);
    }
    logRuntimeTrace(runtimeTrace) {
        if (devvit?.debug.runtime) {
            console.debug('[kmp-dispatcher-perf-analytics]', runtimeTrace);
        }
    }
}
/**
 * The web dispatcher an attempt to give web a unified interface for working with the
 * KMP dispatcher and local/remote runtimes. It also provides a home for a living local
 * runtime reference.
 *
 * The living reference is important because the local runtime is a two step initialization:
 * 1. Initializing the BrowserLiteClient, which creates the web worker
 * 2. Loading the custom post bundle into the web worker to execute
 *
 * It would be inefficient to recreate the worker on every change. It also feels incorrect placing
 * this responsibility onto the devvit-surface lit component.
 *
 * There are two other options to workaround the need for this extra layer:
 * 1. devvit-surface owns the instance of BrowserLiteClient and local runtime takes it in the constructor
 * 2. devvit-surface owns the instance of LocalRuntime. It creates symmetry problems since the RemoteRuntime
 *    is more ephemeral and less expensive to recreate on changes.
 *
 * If you resolve the issue of the LocalRuntime's weight and two step initialization you are still faced
 * with issues around pausing the execution of an app. The WebDispatcher acts as an abstraction layer from
 * the multi-platform code to allow web to stub in temporary solutions until we arrive at consensus across
 * platforms.
 */
initDevvitGlobal();
const makeMillisecondsFromDuration = ({ nanos, seconds, }) => {
    const secondsInMillis = seconds * 1000;
    const nanosInMillis = nanos / 1000000;
    return Math.floor(secondsInMillis + nanosInMillis);
};
// Effects that can only be fired as the result of a user action
const userActionEffects = [
    'showToast',
    'showForm',
    'navigateToUrl',
    'createOrder',
];
export class WebDispatcher {
    get state() {
        return __classPrivateFieldGet(this, _WebDispatcher_dispatcher, "f").state;
    }
    constructor(initialState, env, config) {
        _WebDispatcher_requestBuilder.set(this, void 0);
        _WebDispatcher_timers.set(this, void 0);
        /** The KMP dispatcher that orchestrates events for blocks */
        _WebDispatcher_dispatcher.set(this, void 0);
        /** Invoked at the event of the devvit-surface lifecycle to close the dispatcher listener */
        _WebDispatcher_dispatcherUnsubscribe.set(this, void 0);
        /**
         * Has the post rendered at least once.
         *
         * The new dispatcher doesn't provide a method to let us know if it has been rendered or not.
         * We set it in here to allow to prevent the willUpdate method from submitting infinite
         * render events.
         */
        this.hasRendered = false;
        _WebDispatcher_remoteRuntime.set(this, void 0);
        _WebDispatcher_localRuntime.set(this, void 0);
        _WebDispatcher_pauseSnapshot.set(this, void 0);
        __classPrivateFieldSet(this, _WebDispatcher_requestBuilder, new UIRequestBuilder(env), "f");
        if (config.useSpeculativeExecution && devvit?.debug.runtime) {
            console.debug('[webDispatcher] Using speculative execution mode!');
        }
        __classPrivateFieldSet(this, _WebDispatcher_dispatcher, new JsDispatcherImpl(initialState ?? {}, __classPrivateFieldGet(this, _WebDispatcher_requestBuilder, "f"), RenderPostContent, {
            logger: new Logger(),
            featureFlags: {
                isSpeculativeExecutionEnabled: config.useSpeculativeExecution,
                isUsingEverythingAssembler: false,
                isVerboseLoggingEnabled: !!devvit?.debug.runtime,
            },
            // @ts-expect-error Idk how to work around the type error for __doNotUseOrImplementIt
            performanceAnalyticsDelegate: new UIPerformanceAnalyticsDelegate(),
            errorHandler: (error) => this.onError?.(error),
        }), "f");
        __classPrivateFieldSet(this, _WebDispatcher_timers, new Timers(__classPrivateFieldGet(this, _WebDispatcher_dispatcher, "f")), "f");
        __classPrivateFieldSet(this, _WebDispatcher_remoteRuntime, new RemoteRuntime(), "f");
        __classPrivateFieldSet(this, _WebDispatcher_localRuntime, new LocalRuntime(), "f");
        this.init();
    }
    set metadata(metadata) {
        const copy = { ...metadata };
        const debug = [];
        for (const [k, v] of Object.entries(devvit?.debug ?? {}))
            debug.push(`${k}=${v}`);
        if (debug.length)
            copy[Header.Debug] = { values: debug };
        __classPrivateFieldGet(this, _WebDispatcher_localRuntime, "f").metadata = copy;
        __classPrivateFieldGet(this, _WebDispatcher_remoteRuntime, "f").metadata = copy;
    }
    set onPluginCall(cb) {
        __classPrivateFieldGet(this, _WebDispatcher_localRuntime, "f").onPluginCall = cb;
    }
    set runtimeDebugLogging(runtimeDebugLogging) {
        __classPrivateFieldGet(this, _WebDispatcher_localRuntime, "f").runtimeDebugLogging = runtimeDebugLogging;
    }
    subscribe(cb) {
        __classPrivateFieldSet(this, _WebDispatcher_dispatcherUnsubscribe, __classPrivateFieldGet(this, _WebDispatcher_dispatcher, "f").subscribe((...args) => {
            if (devvit?.debug.runtime)
                console.debug(`[runtime] dispatcher got a new event from subscribe`, args[0]);
            const [{ response }] = args;
            response.uiResponse.effects.forEach((effect) => {
                if (userActionEffects.some((type) => effect[type]) || effect.realtimeSubscriptions) {
                    this.onUserAction?.(effect);
                    return;
                }
                if (effect.interval) {
                    const entries = Object.entries(effect.interval.intervals);
                    if (entries.length === 0) {
                        __classPrivateFieldGet(this, _WebDispatcher_timers, "f").clear();
                    }
                    __classPrivateFieldGet(this, _WebDispatcher_timers, "f").apply(entries.map(([id, meta]) => 
                    // eslint-disable-next-line @typescript-eslint/no-explicit-any
                    new TimerDefinition(id, makeMillisecondsFromDuration(meta.duration))));
                    return;
                }
                console.warn(`Received an effect that is not implemented! Please add an effect handler to the web dispatcher. Effect: ${JSON.stringify(effect, null, 2)}`);
            });
            cb(...args);
        }), "f");
    }
    submit(...args) {
        __classPrivateFieldGet(this, _WebDispatcher_dispatcher, "f").submit(...args);
    }
    unsubscribe() {
        __classPrivateFieldGet(this, _WebDispatcher_dispatcherUnsubscribe, "f")?.unsubscribe();
    }
    init() {
        __classPrivateFieldGet(this, _WebDispatcher_dispatcher, "f").init(__classPrivateFieldGet(this, _WebDispatcher_localRuntime, "f"), __classPrivateFieldGet(this, _WebDispatcher_remoteRuntime, "f"), __classPrivateFieldGet(this, _WebDispatcher_timers, "f"));
    }
    togglePause(pause) {
        if (pause) {
            __classPrivateFieldSet(this, _WebDispatcher_pauseSnapshot, __classPrivateFieldGet(this, _WebDispatcher_dispatcher, "f").pause(), "f");
        }
        else {
            if (__classPrivateFieldGet(this, _WebDispatcher_pauseSnapshot, "f")) {
                __classPrivateFieldGet(this, _WebDispatcher_dispatcher, "f").resume(__classPrivateFieldGet(this, _WebDispatcher_pauseSnapshot, "f"));
            }
        }
    }
    resetAppState() {
        this.hasRendered = false;
        __classPrivateFieldGet(this, _WebDispatcher_dispatcher, "f").reset();
    }
    setEnv(env) {
        __classPrivateFieldGet(this, _WebDispatcher_requestBuilder, "f").env = env;
    }
    setProps(props) {
        __classPrivateFieldGet(this, _WebDispatcher_requestBuilder, "f").props = props;
    }
    remoteLoad(...args) {
        __classPrivateFieldGet(this, _WebDispatcher_remoteRuntime, "f").load(...args);
    }
    async localLoad(...args) {
        __classPrivateFieldGet(this, _WebDispatcher_localRuntime, "f").reset();
        return await __classPrivateFieldGet(this, _WebDispatcher_localRuntime, "f").load(...args);
    }
    localLoadWorker(...args) {
        __classPrivateFieldGet(this, _WebDispatcher_localRuntime, "f").setLocalSrc(...args);
    }
}
_WebDispatcher_requestBuilder = new WeakMap(), _WebDispatcher_timers = new WeakMap(), _WebDispatcher_dispatcher = new WeakMap(), _WebDispatcher_dispatcherUnsubscribe = new WeakMap(), _WebDispatcher_remoteRuntime = new WeakMap(), _WebDispatcher_localRuntime = new WeakMap(), _WebDispatcher_pauseSnapshot = new WeakMap();
//# sourceMappingURL=webDispatcher.js.map