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 _a, _Devvit_appSettings, _Devvit_assets, _Devvit_config, _Devvit_customPostType, _Devvit_formDefinitions, _Devvit_installationSettings, _Devvit_menuItems, _Devvit_scheduledJobHandlers, _Devvit_triggerOnEventHandlers, _Devvit_webviewAssets, _Devvit_additionallyProvides, _Devvit_uses, _Devvit_pluginClients;
import * as protos from '@devvit/protos';
import { Actor } from '@devvit/shared-types/Actor.js';
import { assertValidFormFields } from '../apis/ui/helpers/assertValidFormFields.js';
import { SettingScope } from '../types/index.js';
import { registerAppSettings } from './internals/app-settings.js';
import { registerCustomPost } from './internals/custom-post.js';
import { registerInstallationSettings } from './internals/installation-settings.js';
import { registerMenuItems } from './internals/menu-items.js';
import { pluginIsEnabled } from './internals/plugins.js';
import { registerScheduler } from './internals/scheduler.js';
import { registerTriggers } from './internals/triggers.js';
import { registerUIEventHandler } from './internals/ui-event-handler.js';
import { registerUIRequestHandlers } from './internals/ui-request-handler.js';
export class Devvit extends Actor {
    /**
     * To use certain APIs and features of Devvit, you must enable them using this function.
     *
     * @param config - The configuration object.
     * @param config.http - Enables the HTTP API.
     * @param config.redditAPI - Enables the Reddit API.
     * @param config.kvStore - Enables the Key Value Storage API.
     * @example
     * ```ts
     * Devvit.configure({
     *   http: true,
     *   redditAPI: true,
     *   kvStore: true,
     *   media: true
     * });
     * ```
     */
    static configure(config) {
        __classPrivateFieldSet(this, _a, { ...__classPrivateFieldGet(this, _a, "f", _Devvit_config), ...config }, "f", _Devvit_config);
        if (pluginIsEnabled(config.http)) {
            this.use(protos.HTTPDefinition);
        }
        if (pluginIsEnabled(config.kvStore) || pluginIsEnabled(config.redis)) {
            this.use(protos.KVStoreDefinition);
            this.use(protos.RedisAPIDefinition);
        }
        if (pluginIsEnabled(config.media)) {
            this.use(protos.MediaServiceDefinition);
        }
        if (pluginIsEnabled(config.modLog)) {
            this.use(protos.ModlogDefinition);
        }
        if (pluginIsEnabled(config.redditAPI)) {
            // Loading all Reddit API plugins for now.
            // In the future we can split this by oauth scope or section.
            this.use(protos.FlairDefinition);
            this.use(protos.GraphQLDefinition);
            this.use(protos.LinksAndCommentsDefinition);
            this.use(protos.ListingsDefinition);
            this.use(protos.ModerationDefinition);
            this.use(protos.ModNoteDefinition);
            this.use(protos.NewModmailDefinition);
            this.use(protos.PrivateMessagesDefinition);
            this.use(protos.SubredditsDefinition);
            this.use(protos.UsersDefinition);
            this.use(protos.WidgetsDefinition);
            this.use(protos.WikiDefinition);
        }
        if (pluginIsEnabled(config.realtime)) {
            this.use(protos.RealtimeDefinition);
        }
    }
    /**
     * Add a menu item to the Reddit UI.
     * @param menuItem - The menu item to add.
     * @param menuItem.label - The label of the menu item.
     * @example
     * ```ts
     * Devvit.addMenuItem({
     *   label: 'My Menu Item',
     *   location: 'subreddit',
     *   onPress: (event, context) => {
     *     const location = event.location;
     *     const targetId = event.targetId;
     *     context.ui.showToast(`You clicked on ${location} ${targetId}`);
     *   }
     * });
     * ```
     */
    static addMenuItem(menuItem) {
        __classPrivateFieldGet(this, _a, "f", _Devvit_menuItems).push(menuItem);
    }
    /**
     * Add a custom post type for your app.
     * @param customPostType - The custom post type to add.
     * @param customPostType.name - The name of the custom post type.
     * @param customPostType.description - An optional description.
     * @param customPostType.height - An optional parameter to set post height, defaults to 'regular'.
     * @param customPostType.render - A function or `Devvit.CustomPostComponent` that returns the UI for the custom post.
     * @example
     * ```ts
     * import { Devvit, useState } from '@devvit/public-api';
     *
     * Devvit.addCustomPostType({
     *   name: 'Counter',
     *   description: 'A simple click counter post.',
     *   render: (context) => {
     *     const [counter, setCounter] = useState();
     *
     *     return (
     *       <vstack>
     *         <text>{counter}</text>
     *       <button onPress={() => setCounter((counter) => counter + 1)}>Click me!</button>
     *     </vstack>
     *   );
     *   },
     * });
     * ```
     */
    static addCustomPostType(customPostType) {
        __classPrivateFieldSet(this, _a, customPostType, "f", _Devvit_customPostType);
    }
    /**
     * Create a form that can be opened from menu items and custom posts.
     * @param form - The form or a function that returns the form.
     * @param onSubmit - The function to call when the form is submitted.
     * @returns A unique key for the form that can used with `ui.showForm`.
     */
    static createForm(form, onSubmit) {
        const formKey = `form.${__classPrivateFieldGet(this, _a, "f", _Devvit_formDefinitions).size}`;
        __classPrivateFieldGet(this, _a, "f", _Devvit_formDefinitions).set(formKey, {
            form,
            onSubmit,
        });
        return formKey;
    }
    /**
     * Add a scheduled job type for your app. This will allow you to schedule jobs using the `scheduler` API.
     * @param job - The scheduled job type to add.
     * @param job.name - The name of the scheduled job type.
     * @param job.onRun - The function to call when the scheduled job is run.
     * @example
     * ```ts
     * Devvit.addSchedulerJob({
     *   name: 'checkNewPosts',
     *   onRun: async (event, context) => {
     *     const newPosts = await context.reddit.getNewPosts({ limit: 5 }).all();
     *     for (const post of newPosts) {
     *       if (post.title.includes('bad word')) {
     *         await post.remove();
     *       }
     *     }
     *   }
     * });
     *
     * Devvit.addMenuItem({
     *   label: 'Check for new posts',
     *   location: 'location',
     *   onPress: (event, context) => {
     *     const = await context.scheduler.runJob({
     *       name: 'checkNewPosts',
     *       when: new Date(Date.now() + 5000) // in 5 seconds
     *     });
     *   }
     * });
     * ```
     */
    static addSchedulerJob(job) {
        if (!__classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[protos.SchedulerDefinition.fullName]) {
            this.use(protos.SchedulerDefinition);
        }
        if (__classPrivateFieldGet(this, _a, "f", _Devvit_scheduledJobHandlers).has(job.name)) {
            throw new Error(`Job ${job.name} is already defined`);
        }
        __classPrivateFieldGet(this, _a, "f", _Devvit_scheduledJobHandlers).set(job.name, job.onRun);
    }
    /**
     * Add settings that can be configured to customize the behavior of your app. There are two levels of settings: App settings (scope: 'app') and
     * install settings (scope: 'installation' or unspecified scope). Install settings are meant to be configured by the user that installs your app.
     * This is a good place to add anything that a user might want to change to personalize the app (e.g. the default city to show the weather for or a
     * specific sport team that a subreddit follows). Note that these are good for subreddit level customization but not necessarily good for things
     * that might be different for two users in a subreddit (e.g. setting the default city to show the weather for is only useful at a sub level if
     * the sub is for a specific city or region). Install settings can be viewed and configured here: https://developers.reddit.com/r/subreddit-name/apps/app-name.
     * App settings can be accessed and consumed by all installations of the app. This is mainly useful for developer secrets/API keys that your
     * app needs to function. They can only be changed/viewed by you via the CLI (devvit settings set and devvit settings list). This ensures secrets
     * are persisted in an encrypted store and don't get committed in the source code. You should never paste your actual key into any fields passed into
     * Devvit.addSettings - this is merely where you state what your API key's name and description are. You will be able to set the actual value of the key via CLI.
     * Note: setting names must be unique across all settings.
     * @param fields - Fields for the app and installation settings.
     * @example
     * ```ts
     * Devvit.addSettings([
     *   {
     *     type: 'string',
     *     name: 'weather-api-key',
     *     label: 'My weather.com API key',
     *     scope: SettingScope.App,
     *     isSecret: true
     *   },
     *   {
     *     type: 'string',
     *     name: 'Default City',
     *     label: 'Default city to show the weather for by default',
     *     scope: SettingScope.Installation,
     *     onValidate: ({ value }) => {
     *       if (!isValidCity(value)) {
     *         return 'You must ender a valid city: ${validCities.join(", ")}';
     *       }
     *     }
     *   },
     *   {
     *     type: 'number',
     *     name: 'Default Forecast Window (in days)',
     *     label: 'The number of days to show for forecast for by default',
     *     scope: SettingScope.Installation,
     *     onValidate: ({ value }) => {
     *       if (value > 10 || value < 1) {
     *         return 'Forecast window must be from 1 to 10 days';
     *       }
     *     }
     *   },
     * ]);
     * ```
     */
    static addSettings(fields) {
        assertValidFormFields(fields);
        const installSettings = fields.filter((field) => field.type === 'group' || !field.scope || field.scope === SettingScope.Installation);
        const appSettings = fields.filter((field) => field.type !== 'group' && field.scope === SettingScope.App);
        if (installSettings.length > 0) {
            __classPrivateFieldSet(this, _a, installSettings, "f", _Devvit_installationSettings);
        }
        if (appSettings.length > 0) {
            __classPrivateFieldSet(this, _a, appSettings, "f", _Devvit_appSettings);
        }
        if (!__classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[protos.SettingsDefinition.fullName]) {
            this.use(protos.SettingsDefinition);
        }
    }
    static addTrigger(triggerDefinition) {
        if ('events' in triggerDefinition) {
            for (const eventType of triggerDefinition.events) {
                this.addTrigger({
                    event: eventType,
                    onEvent: (event, context) => triggerDefinition.onEvent(event, context),
                }); // eslint-disable-line @typescript-eslint/no-explicit-any
            }
            return this;
        }
        if (__classPrivateFieldGet(this, _a, "f", _Devvit_triggerOnEventHandlers).has(triggerDefinition.event)) {
            __classPrivateFieldGet(this, _a, "f", _Devvit_triggerOnEventHandlers)
                .get(triggerDefinition.event)
                ?.push(triggerDefinition.onEvent);
        }
        else {
            __classPrivateFieldGet(this, _a, "f", _Devvit_triggerOnEventHandlers).set(triggerDefinition.event, [
                triggerDefinition.onEvent,
            ]);
        }
        return _a;
    }
    /**
     * @internal
     * utility static method to register additional actor types without exposing an explicit
     * registration hook such as `addTrigger` or `addMenuItem`
     */
    static provide(def) {
        __classPrivateFieldGet(this, _a, "f", _Devvit_additionallyProvides).push(def);
    }
    /** @internal */
    static use(d, opts) {
        __classPrivateFieldGet(this, _a, "f", _Devvit_uses)[d.fullName] = {
            def: d,
            options: opts ?? {},
            handler: undefined,
        };
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const wrapped = {};
        for (const method of Object.values(d.methods)) {
            wrapped[method.name] = (args, metadata) => __classPrivateFieldGet(this, _a, "f", _Devvit_uses)[d.fullName].handler?.[method.name]?.(method.requestType?.fromPartial(args ?? {}), metadata);
        }
        __classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[d.fullName] = wrapped;
        return wrapped;
    }
    /** @internal */
    static get redditAPIPlugins() {
        if (!pluginIsEnabled(__classPrivateFieldGet(this, _a, "f", _Devvit_config).redditAPI)) {
            throw new Error('Reddit API is not enabled. You can enable it by passing `redditAPI: true` to `Devvit.configure`.');
        }
        return {
            Flair: __classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[protos.FlairDefinition.fullName],
            GraphQL: __classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[protos.GraphQLDefinition.fullName],
            LinksAndComments: __classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[protos.LinksAndCommentsDefinition.fullName],
            Listings: __classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[protos.ListingsDefinition.fullName],
            Moderation: __classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[protos.ModerationDefinition.fullName],
            ModNote: __classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[protos.ModNoteDefinition.fullName],
            NewModmail: __classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[protos.NewModmailDefinition.fullName],
            PrivateMessages: __classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[protos.PrivateMessagesDefinition.fullName],
            Subreddits: __classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[protos.SubredditsDefinition.fullName],
            Users: __classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[protos.UsersDefinition.fullName],
            Widgets: __classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[protos.WidgetsDefinition.fullName],
            Wiki: __classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[protos.WikiDefinition.fullName],
        };
    }
    /** @internal */
    static get modLogPlugin() {
        const modLog = __classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[protos.ModlogDefinition.fullName];
        if (!modLog) {
            throw new Error('ModLog is not enabled. You can enable it by passing `modLog: true` to `Devvit.configure`');
        }
        return modLog;
    }
    /** @internal */
    static get schedulerPlugin() {
        const scheduler = __classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[protos.SchedulerDefinition.fullName];
        if (!scheduler) {
            // todo: better error with more details
            throw new Error('Scheduler is not enabled. You can enable it by calling `Devvit.addSchedulerJob` at the top level of your app.');
        }
        return scheduler;
    }
    /** @internal */
    static get kvStorePlugin() {
        const kvStore = __classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[protos.KVStoreDefinition.fullName];
        if (!kvStore) {
            throw new Error('Key Value Store is not enabled. You can enable it by passing `kvStore: true` to `Devvit.configure`');
        }
        return kvStore;
    }
    /** @internal */
    static get redisPlugin() {
        const redis = __classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[protos.RedisAPIDefinition.fullName];
        if (!redis) {
            throw new Error('Redis is not enabled. You can enable it by passing `redis: true` to `Devvit.configure`');
        }
        return redis;
    }
    /** @internal */
    static get mediaPlugin() {
        const media = __classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[protos.MediaServiceDefinition.fullName];
        if (!media) {
            throw new Error('MediaService is not enabled. You can enable it by passing `media: true` to `Devvit.configure`');
        }
        return media;
    }
    /** @internal */
    static get settingsPlugin() {
        const settings = __classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[protos.SettingsDefinition.fullName];
        if (!settings) {
            throw new Error('Settings must first be configured with `Devvit.addSettings()` before they can be accessed');
        }
        return settings;
    }
    /** @internal */
    static get realtimePlugin() {
        const realtime = __classPrivateFieldGet(this, _a, "f", _Devvit_pluginClients)[protos.RealtimeDefinition.fullName];
        if (!realtime) {
            throw new Error('Realtime is not enabled. You can enable it by passing `realtime: true` to `Devvit.configure`');
        }
        return realtime;
    }
    /** @internal */
    static get menuItems() {
        return __classPrivateFieldGet(this, _a, "f", _Devvit_menuItems);
    }
    /** @internal */
    static get customPostType() {
        return __classPrivateFieldGet(this, _a, "f", _Devvit_customPostType);
    }
    /** @internal */
    static get formDefinitions() {
        return __classPrivateFieldGet(this, _a, "f", _Devvit_formDefinitions);
    }
    /** @internal */
    static get scheduledJobHandlers() {
        return __classPrivateFieldGet(this, _a, "f", _Devvit_scheduledJobHandlers);
    }
    /** @internal */
    static get installationSettings() {
        return __classPrivateFieldGet(this, _a, "f", _Devvit_installationSettings);
    }
    /** @internal */
    static get appSettings() {
        return __classPrivateFieldGet(this, _a, "f", _Devvit_appSettings);
    }
    /** @internal */
    static get triggerOnEventHandlers() {
        return __classPrivateFieldGet(this, _a, "f", _Devvit_triggerOnEventHandlers);
    }
    /** @internal */
    static get assets() {
        return __classPrivateFieldGet(this, _a, "f", _Devvit_assets);
    }
    /** @internal */
    static get webviewAssets() {
        return __classPrivateFieldGet(this, _a, "f", _Devvit_webviewAssets);
    }
    /** @internal */
    constructor(config) {
        super(config);
        __classPrivateFieldSet(_a, _a, config.assets ?? {}, "f", _Devvit_assets);
        __classPrivateFieldSet(_a, _a, config.webviewAssets ?? {}, "f", _Devvit_webviewAssets);
        for (const fullName in __classPrivateFieldGet(_a, _a, "f", _Devvit_uses)) {
            const use = __classPrivateFieldGet(_a, _a, "f", _Devvit_uses)[fullName];
            use.handler = config.use(use.def, use.options);
        }
        if (__classPrivateFieldGet(_a, _a, "f", _Devvit_menuItems).length > 0) {
            registerMenuItems(config);
        }
        if (__classPrivateFieldGet(_a, _a, "f", _Devvit_scheduledJobHandlers).size > 0) {
            registerScheduler(config);
        }
        if (__classPrivateFieldGet(_a, _a, "f", _Devvit_customPostType)) {
            registerCustomPost(config);
            /**
             * We're trying to migrate custom posts to generic ui handlers, but they'll
             * both work for now.
             */
            registerUIRequestHandlers(config);
        }
        if (__classPrivateFieldGet(_a, _a, "f", _Devvit_customPostType) || __classPrivateFieldGet(_a, _a, "f", _Devvit_formDefinitions).size > 0) {
            registerUIEventHandler(config);
        }
        if (__classPrivateFieldGet(_a, _a, "f", _Devvit_installationSettings)) {
            registerInstallationSettings(config);
        }
        if (__classPrivateFieldGet(_a, _a, "f", _Devvit_appSettings)) {
            registerAppSettings(config);
        }
        if (__classPrivateFieldGet(_a, _a, "f", _Devvit_triggerOnEventHandlers).size > 0) {
            registerTriggers(config);
        }
        for (const provides of __classPrivateFieldGet(_a, _a, "f", _Devvit_additionallyProvides)) {
            config.provides(provides);
        }
    }
}
_a = Devvit;
Devvit.debug = {};
_Devvit_appSettings = { value: void 0 };
_Devvit_assets = { value: {} };
_Devvit_config = { value: {} };
_Devvit_customPostType = { value: void 0 };
_Devvit_formDefinitions = { value: new Map() };
_Devvit_installationSettings = { value: void 0 };
_Devvit_menuItems = { value: [] };
_Devvit_scheduledJobHandlers = { value: new Map() };
_Devvit_triggerOnEventHandlers = { value: new Map() };
_Devvit_webviewAssets = { value: {} };
_Devvit_additionallyProvides = { value: [] };
/** @internal */
_Devvit_uses = { value: {} };
/** @internal */
_Devvit_pluginClients = { value: {} };
(function (Devvit) {
    function createElement(type, props, ...children) {
        const blockElement = {
            type,
            props,
            children,
        };
        return blockElement;
    }
    Devvit.createElement = createElement;
})(Devvit || (Devvit = {}));
