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 __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 _BootstrapActor_dispatcher, _BootstrapActor_loadedActor, _BootstrapActor_logger;
import { Definition } from '@devvit/protos/lib/Types.js';
import { Empty } from '@devvit/protos/types/google/protobuf/empty.js';
// eslint-disable-next-line @benasher44/implicit-dependencies/no-implicit
import runtimes from '@devvit/runtimes/package.json';
import { StringUtil } from '@devvit/shared-types/StringUtil.js';
import { Log } from '../../lib/loggers/Log.js';
import { dangerouslyGetBundleActor } from '../bundle/BundleModule.js';
import { Config } from '../bundle/Config.js';
import LinkedBundleClientFactory from '../bundle/LinkedBundleClientFactory.js';
import { EnvelopeServerBuilder } from '../envelope/EnvelopeServerBuilder.js';
/**
 * Provides the functionality required to load an Actor into the current Worker
 */
export class BootstrapActor {
    constructor(dispatcher, logger) {
        _BootstrapActor_dispatcher.set(this, void 0);
        _BootstrapActor_loadedActor.set(this, false);
        _BootstrapActor_logger.set(this, void 0);
        __classPrivateFieldSet(this, _BootstrapActor_dispatcher, dispatcher, "f");
        __classPrivateFieldSet(this, _BootstrapActor_logger, logger, "f");
    }
    async IsResponding(mt) {
        return mt;
    }
    /**
     * Registers this worker as an Actor as defined by bundle
     */
    // RPC
    async LoadActor(bundle, _metadata) {
        if (__classPrivateFieldGet(this, _BootstrapActor_loadedActor, "f")) {
            await Log.warn(`${bundle.hostname} already loaded.`);
            return Empty.fromPartial({});
        }
        const nameVersion = `${bundle.hostname} v${bundle.actor?.version ?? '?.?.?'}`;
        if (bundle.buildInfo != null && !isBuiltForRuntimes(bundle.buildInfo)) {
            const buildVersion = bundle.buildInfo.dependencies[runtimes.name] ?? '?.?.?';
            const created = bundle.buildInfo.created?.toISOString().slice(0, -5) ?? '?';
            await Log.info(`${nameVersion} was built for ${runtimes.name} v${buildVersion} and ` +
                `created ${created}; currently executing on v${runtimes.version}. ` +
                'This is probably ok.');
        }
        await Log.verbose(`Initializing ${nameVersion}.`);
        try {
            const ActorClass = await dangerouslyGetBundleActor(bundle.code);
            // Configure and create a new instance of Actor. Any clients the actor
            // depends on (uses) are created here and bound to the dispatcher. The
            // dispatcher routes the requests to the upstream envelope port where they
            // leave the worker and are observed by the central dispatcher.
            const clients = new LinkedBundleClientFactory(__classPrivateFieldGet(this, _BootstrapActor_dispatcher, "f"), bundle, __classPrivateFieldGet(this, _BootstrapActor_logger, "f"));
            const cfg = new Config(clients, bundle.actor, bundle.assets, bundle.webviewAssets);
            globalThis.devvit ?? (globalThis.devvit = {});
            globalThis.devvit.config = cfg;
            const svc = new ActorClass(cfg);
            // Ensure actor exposes at least one service.
            // to-do: test `bundle.provides.length === 0`. `bundle.provides` is always
            // truthy.
            if (!bundle.provides)
                throw Error(`${nameVersion} provides no services.`);
            // Register the Actor instance with each declared provides at the URI.
            // This is the Worker's one and only server for everything this Worker
            // provides except the bootstrap. This makes sense because there's
            // nothing else to route to--either it's in our server or it's not. The
            // server binds the actor and dispatcher together so that request
            // envelopes for provide methods route to it.
            const server = EnvelopeServerBuilder.build(bundle.hostname, bundle.provides.map((p) => Definition.fromSerializable(p)), svc, __classPrivateFieldGet(this, _BootstrapActor_logger, "f"));
            __classPrivateFieldGet(this, _BootstrapActor_dispatcher, "f").bind(server);
            await Log.info(`${nameVersion} initialized.`);
            __classPrivateFieldSet(this, _BootstrapActor_loadedActor, true, "f");
        }
        catch (err) {
            await Log.error(`${nameVersion} initialization failure: ${StringUtil.caughtToString(err)}`);
            throw err;
        }
        return Empty.fromPartial({});
    }
}
_BootstrapActor_dispatcher = new WeakMap(), _BootstrapActor_loadedActor = new WeakMap(), _BootstrapActor_logger = new WeakMap();
function isBuiltForRuntimes(info) {
    return info.dependencies[runtimes.name] === runtimes.version;
}
