var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
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 _DevvitSurface_instances, _DevvitSurface_rootHeight, _DevvitSurface_resizeObserver, _DevvitSurface_intersectionObserver, _DevvitSurface_appVersion, _DevvitSurface_dispatcher, _DevvitSurface_newRenderContext, _DevvitSurface_onError, _DevvitSurface_onPluginCall, _DevvitSurface_onRender, _DevvitSurface_bubble, _DevvitSurface_onUserActionEffect;
import '@reddit/faceplate-ui/templateRenderingStrategy/clientStrategy.js';
import '../blocks/components/devvit-blocks-renderer.js';
import '../blocks/components/devvit-blocks-webview.js';
import { BlockStackDirection, RealtimeDefinition, UIEventScope } from '@devvit/protos';
import { UIDimensions } from '@devvit/protos/types/devvit/ui/common/v1alpha/common.js';
import { isCircuitBreaker } from '@devvit/shared-types/CircuitBreaker.js';
import { Header } from '@devvit/shared-types/Header.js';
import { throttle } from '@devvit/shared-types/throttle.js';
import { asT3ID } from '@devvit/shared-types/tid.js';
import { customEvent } from '@reddit/faceplate/lib/custom-event.js';
import { html, LitElement } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { DEFAULT_ROOT_HEIGHT } from '../blocks/templates/renderBlock.js';
import { styles } from '../styles.js';
import { buildDimensions } from './dimensions.js';
import { DevvitClientPerformanceEventName } from './dispatcher/events.js';
import { WrappedEvent } from './dispatcher/mappers.js';
import { WebDispatcher } from './dispatcher/webDispatcher.js';
import { resolveWebviewUrl } from './webview.js';
/**
 * A component for rendering blocks somewhere inside of Reddit. This component should
 * have no opinions on where it is rendered, only that the props are supplied.
 *
 * The complexity of this class should only be the UI itself and proxying state
 * to devvit-blocks-renderer and Dispatcher. Don't put logic here that you can't
 * unit test.
 *
 * @slot - Loading / unloaded state.
 */
let DevvitSurface = class DevvitSurface extends LitElement {
    static get styles() {
        return [styles];
    }
    constructor() {
        super();
        _DevvitSurface_instances.add(this);
        /** Enables debug logging for the local runtime */
        this.runtimeDebugLogging = false;
        /** Enable the use of experimental blocks that are not production ready */
        this.useExperimentalBlocks = false;
        /** Enable the use of speculative execution from within KMP */
        this.useSpeculativeExecution = false;
        this.webviewUrlTemplate = '';
        this.disableAssetSandbox = false;
        _DevvitSurface_rootHeight.set(this, void 0);
        _DevvitSurface_resizeObserver.set(this, void 0);
        _DevvitSurface_intersectionObserver.set(this, void 0);
        _DevvitSurface_appVersion.set(this, '');
        /** The orchestrates events for blocks */
        _DevvitSurface_dispatcher.set(this, void 0);
        _DevvitSurface_newRenderContext.set(this, () => ({
            experimental: this.useExperimentalBlocks,
            resolveWebviewUrl: (url) => this.disableAssetSandbox
                ? url
                : resolveWebviewUrl(this.webviewUrlTemplate, this.metadata?.[Header.Subreddit]?.values?.[0], __classPrivateFieldGet(this, _DevvitSurface_appVersion, "f"), url),
            onAction: (action) => __classPrivateFieldGet(this, _DevvitSurface_dispatcher, "f")?.submit([
                new WrappedEvent({
                    scope: UIEventScope.ALL,
                    userAction: {
                        actionId: action.id,
                        data: action.data ?? {},
                    },
                    hook: action.id,
                }),
            ]),
            stackDirection: BlockStackDirection.UNRECOGNIZED,
            disableAssetSandbox: this.disableAssetSandbox,
        }));
        _DevvitSurface_onError.set(this, (err) => {
            if (!isCircuitBreaker(err))
                console.error(err);
            __classPrivateFieldGet(this, _DevvitSurface_instances, "m", _DevvitSurface_bubble).call(this, 'devvit-ui-error', { err, type: 'Error' });
        });
        _DevvitSurface_onPluginCall.set(this, (_id, serviceName, method, args, _meta) => {
            if (serviceName === RealtimeDefinition.fullName &&
                method === RealtimeDefinition.methods.send.name)
                __classPrivateFieldGet(this, _DevvitSurface_instances, "m", _DevvitSurface_bubble).call(this, 'devvit-realtime-send', { event: args });
        });
        _DevvitSurface_onRender.set(this, ({ response }) => {
            var _a, _b;
            this.renderResponse = response;
            if (response?.blocks) {
                this._rootBlock = response.blocks;
                if (!__classPrivateFieldGet(this, _DevvitSurface_rootHeight, "f")) {
                    // Lock in the initial height
                    __classPrivateFieldSet(this, _DevvitSurface_rootHeight, this._rootBlock.config?.rootConfig?.height || DEFAULT_ROOT_HEIGHT, "f");
                }
                else {
                    (_a = this._rootBlock).config ?? (_a.config = {});
                    (_b = this._rootBlock.config).rootConfig ?? (_b.rootConfig = { children: [], height: 0 });
                    this._rootBlock.config.rootConfig.height = __classPrivateFieldGet(this, _DevvitSurface_rootHeight, "f");
                }
            }
        });
        _DevvitSurface_onUserActionEffect.set(this, (fx) => {
            __classPrivateFieldGet(this, _DevvitSurface_instances, "m", _DevvitSurface_bubble).call(this, 'devvit-ui-effect', {
                effect: fx,
                onEvent: (ev) => __classPrivateFieldGet(this, _DevvitSurface_dispatcher, "f")?.submit([new WrappedEvent(ev)]),
                metadata: this.metadata,
            });
        });
        if (devvit?.debug.surface)
            console.debug(`[surface] Using devvit-surface and KMP!`);
    }
    async connectedCallback() {
        super.connectedCallback();
        // This can't go in the constructor since we require feature flags. Sad!
        __classPrivateFieldSet(this, _DevvitSurface_dispatcher, new WebDispatcher({}, {
            colorScheme: this.scheme,
            dimensions: this.dimensions,
            locale: this.metadata?.[Header.Language]?.values?.[0],
            timezone: this.metadata?.[Header.Timezone]?.values?.[0],
        }, {
            useSpeculativeExecution: this.useSpeculativeExecution,
        }), "f");
        __classPrivateFieldGet(this, _DevvitSurface_dispatcher, "f").onPluginCall = __classPrivateFieldGet(this, _DevvitSurface_onPluginCall, "f");
        __classPrivateFieldGet(this, _DevvitSurface_dispatcher, "f").onError = __classPrivateFieldGet(this, _DevvitSurface_onError, "f");
        __classPrivateFieldGet(this, _DevvitSurface_dispatcher, "f").onUserAction = __classPrivateFieldGet(this, _DevvitSurface_onUserActionEffect, "f");
        __classPrivateFieldGet(this, _DevvitSurface_dispatcher, "f").subscribe((params) => {
            __classPrivateFieldGet(this, _DevvitSurface_onRender, "f").call(this, {
                request: params.request.uiRequest,
                response: params.response.uiResponse,
            });
        });
        __classPrivateFieldSet(this, _DevvitSurface_resizeObserver, new ResizeObserver(throttle((entries) => {
            if (entries.length === 0)
                return;
            this.dimensions = buildDimensions(entries[0], window, document.body);
        }, 600)), "f");
        __classPrivateFieldGet(this, _DevvitSurface_resizeObserver, "f").observe(this, { box: 'content-box' });
        __classPrivateFieldSet(this, _DevvitSurface_intersectionObserver, new IntersectionObserver((entries) => {
            entries.forEach((entry) => {
                __classPrivateFieldGet(this, _DevvitSurface_dispatcher, "f")?.togglePause(!entry.isIntersecting);
            });
        }), "f");
        __classPrivateFieldGet(this, _DevvitSurface_intersectionObserver, "f").observe(this);
    }
    disconnectedCallback() {
        __classPrivateFieldGet(this, _DevvitSurface_resizeObserver, "f")?.unobserve(this);
        __classPrivateFieldGet(this, _DevvitSurface_resizeObserver, "f")?.disconnect();
        __classPrivateFieldGet(this, _DevvitSurface_intersectionObserver, "f")?.unobserve(this);
        __classPrivateFieldGet(this, _DevvitSurface_intersectionObserver, "f")?.disconnect();
        __classPrivateFieldGet(this, _DevvitSurface_dispatcher, "f")?.unsubscribe();
        super.disconnectedCallback();
    }
    render() {
        if (!this.renderResponse) {
            // The slot content is considered the loading state.
            return html `<slot></slot>`;
        }
        return html `<div class="relative">
      <devvit-blocks-renderer
        class="${this.scheme ?? ''}"
        .block="${this._rootBlock}"
        .renderContext="${__classPrivateFieldGet(this, _DevvitSurface_newRenderContext, "f")}"
      >
        <slot slot="empty-state-image" name="empty-state-image"></slot>
      </devvit-blocks-renderer>
    </div>`;
    }
    async willUpdate(props) {
        if (!__classPrivateFieldGet(this, _DevvitSurface_dispatcher, "f"))
            return;
        // Keep the env up to date as things change
        __classPrivateFieldGet(this, _DevvitSurface_dispatcher, "f").setEnv({
            colorScheme: this.scheme,
            dimensions: this.dimensions,
            locale: this.metadata?.[Header.Language]?.values?.[0],
            timezone: this.metadata?.[Header.Timezone]?.values?.[0],
        });
        __classPrivateFieldGet(this, _DevvitSurface_dispatcher, "f").setProps({
            ...this.requestProps,
            postId: this.requestProps?.postId ? asT3ID(this.requestProps.postId) : undefined,
        });
        __classPrivateFieldGet(this, _DevvitSurface_dispatcher, "f").runtimeDebugLogging = this.runtimeDebugLogging;
        __classPrivateFieldGet(this, _DevvitSurface_dispatcher, "f").metadata = this.metadata;
        if (props.has('remoteApp')) {
            if (devvit?.debug.surface)
                console.debug(`[surface] remoteApp ${this.remoteApp ? 'defined' : 'undefined'}`);
            __classPrivateFieldGet(this, _DevvitSurface_dispatcher, "f").remoteLoad(this.remoteApp);
        }
        if (props.has('localRuntimeCode')) {
            if (devvit?.debug.surface)
                console.debug(`[surface] local runtime ${this.localRuntimeCode ? 'loading' : 'unloading'}`);
            __classPrivateFieldGet(this, _DevvitSurface_dispatcher, "f").localLoadWorker(this.localRuntimeCode);
        }
        if (props.has('bundle') && this.bundle) {
            if (devvit?.debug.surface)
                console.debug(`[surface] bundle loading`);
            const rsp = await __classPrivateFieldGet(this, _DevvitSurface_dispatcher, "f").localLoad(this.bundle);
            if (rsp) {
                __classPrivateFieldGet(this, _DevvitSurface_instances, "m", _DevvitSurface_bubble).call(this, DevvitClientPerformanceEventName, {
                    name: 'init_runtime',
                    duration: Math.round(rsp.metrics.init.end - rsp.metrics.init.start),
                });
                if (rsp.metrics.loadBundle) {
                    __classPrivateFieldGet(this, _DevvitSurface_instances, "m", _DevvitSurface_bubble).call(this, DevvitClientPerformanceEventName, {
                        name: 'load_full_bundle',
                        duration: Math.round(rsp.metrics.loadBundle.end - rsp.metrics.loadBundle.start),
                    });
                }
            }
            if (devvit?.debug.surface)
                console.debug('[surface] bundle loaded');
            __classPrivateFieldSet(this, _DevvitSurface_appVersion, this.bundle.actor?.version ?? '', "f");
            if (props.get('bundle')) {
                if (devvit?.debug.surface)
                    console.debug('[runtime][surface] reset runtime state');
                __classPrivateFieldSet(this, _DevvitSurface_rootHeight, undefined, "f");
                this.renderResponse = undefined;
                // Bundle was _replaced_ (likely devvit-preview). Require a new render.
                __classPrivateFieldGet(this, _DevvitSurface_dispatcher, "f").resetAppState();
            }
        }
        // If the custom post does not have dimensions, block all render events until they are
        // reported. This prevents the user from being shown the jank of our custom dimensions.
        // Do not place this above the bundle loader! We want to start loading immediately
        // since it can take a few seconds.
        //
        // In case you're curious, this adds about 15ms of latency, but that pales in comparison
        // to the length of loading the local runtime.
        if (!this.dimensions)
            return;
        // We always want to trigger at least one render if:
        // 1. The app dimensions change
        // 2. The bundle changes. Loading a bundle is lengthy and dimensions may have changed during a load
        if (!__classPrivateFieldGet(this, _DevvitSurface_dispatcher, "f").hasRendered || props.has('bundle')) {
            __classPrivateFieldGet(this, _DevvitSurface_dispatcher, "f").hasRendered = true;
            __classPrivateFieldGet(this, _DevvitSurface_dispatcher, "f").submit([
                new WrappedEvent({
                    scope: UIEventScope.ALL,
                    blocking: {},
                }),
            ]);
        }
        else if (props.has('dimensions')) {
            __classPrivateFieldGet(this, _DevvitSurface_dispatcher, "f").submit([
                new WrappedEvent({
                    scope: UIEventScope.ALL,
                    resize: {},
                }),
            ]);
        }
    }
};
_DevvitSurface_rootHeight = new WeakMap();
_DevvitSurface_resizeObserver = new WeakMap();
_DevvitSurface_intersectionObserver = new WeakMap();
_DevvitSurface_appVersion = new WeakMap();
_DevvitSurface_dispatcher = new WeakMap();
_DevvitSurface_newRenderContext = new WeakMap();
_DevvitSurface_onError = new WeakMap();
_DevvitSurface_onPluginCall = new WeakMap();
_DevvitSurface_onRender = new WeakMap();
_DevvitSurface_onUserActionEffect = new WeakMap();
_DevvitSurface_instances = new WeakSet();
_DevvitSurface_bubble = function _DevvitSurface_bubble(type, detail) {
    this.dispatchEvent(customEvent(type, detail));
};
__decorate([
    property({ attribute: false }),
    __metadata("design:type", Object)
], DevvitSurface.prototype, "remoteApp", void 0);
__decorate([
    property({ attribute: false }),
    __metadata("design:type", Object)
], DevvitSurface.prototype, "bundle", void 0);
__decorate([
    property({ attribute: false }),
    __metadata("design:type", Object)
], DevvitSurface.prototype, "localRuntimeCode", void 0);
__decorate([
    property({ attribute: false }),
    __metadata("design:type", Object)
], DevvitSurface.prototype, "metadata", void 0);
__decorate([
    property({ attribute: 'requestProps', type: Object }),
    __metadata("design:type", Object)
], DevvitSurface.prototype, "requestProps", void 0);
__decorate([
    property({ attribute: 'runtime-debug-logging', type: Boolean }),
    __metadata("design:type", Boolean)
], DevvitSurface.prototype, "runtimeDebugLogging", void 0);
__decorate([
    property({ attribute: 'scheme' }),
    __metadata("design:type", Object)
], DevvitSurface.prototype, "scheme", void 0);
__decorate([
    property({ attribute: 'use-experimental-blocks', type: Boolean }),
    __metadata("design:type", Boolean)
], DevvitSurface.prototype, "useExperimentalBlocks", void 0);
__decorate([
    property({ attribute: 'use-speculative-execution', type: Boolean }),
    __metadata("design:type", Boolean)
], DevvitSurface.prototype, "useSpeculativeExecution", void 0);
__decorate([
    property({ type: String }),
    __metadata("design:type", String)
], DevvitSurface.prototype, "webviewUrlTemplate", void 0);
__decorate([
    property({ attribute: 'disable-asset-sandbox', type: Boolean }),
    __metadata("design:type", Boolean)
], DevvitSurface.prototype, "disableAssetSandbox", void 0);
__decorate([
    state(),
    __metadata("design:type", Object)
], DevvitSurface.prototype, "dimensions", void 0);
__decorate([
    state(),
    __metadata("design:type", Object)
], DevvitSurface.prototype, "_rootBlock", void 0);
DevvitSurface = __decorate([
    customElement('devvit-surface'),
    __metadata("design:paramtypes", [])
], DevvitSurface);
export { DevvitSurface };
//# sourceMappingURL=devvit-surface.js.map