import '../WorkerInit.js';
import { FlairDefinition, GraphQLDefinition, HTTPDefinition, LinksAndCommentsDefinition, ListingsDefinition, ModerationDefinition, ModNoteDefinition, NewModmailDefinition, PrivateMessagesDefinition, SubredditsDefinition, UsersDefinition, WidgetsDefinition, WikiDefinition, } from '@devvit/protos';
import { WorkerDispatcher } from '../../common/envelope/dispatcher/WorkerDispatcher.js';
import { EnvelopeClientBuilder } from '../../common/envelope/EnvelopeClientBuilder.js';
import { EnvelopeServerBuilder } from '../../common/envelope/EnvelopeServerBuilder.js';
import { childHostname, resolvePluginHostname } from '@devvit/shared-types/HostnameUtil.js';
import { Log } from '../../lib/loggers/Log.js';
import { Flair } from '../../plugins/redditapi/Flair.js';
import { LinksAndComments } from '../../plugins/redditapi/LinksAndComments.js';
import { Listings } from '../../plugins/redditapi/Listings.js';
import { Moderation } from '../../plugins/redditapi/Moderation.js';
import { ModNote } from '../../plugins/redditapi/ModNote.js';
import { NewModmail } from '../../plugins/redditapi/NewModmail.js';
import { PrivateMessages } from '../../plugins/redditapi/PrivateMessages.js';
import { Subreddits } from '../../plugins/redditapi/Subreddits.js';
import { Users } from '../../plugins/redditapi/Users.js';
import { Widgets } from '../../plugins/redditapi/Widgets.js';
import { Wiki } from '../../plugins/redditapi/Wiki.js';
import { GraphQL } from '../../plugins/redditapi/GraphQL.js';
// Create an RPC wrapper around the port
const dispatcher = new WorkerDispatcher(self.name);
dispatcher.bindToWorkerPort(self);
const apiCategories = [
    {
        cname: 'listings',
        constructor: Listings,
        definition: ListingsDefinition,
    },
    {
        cname: 'modnote',
        constructor: ModNote,
        definition: ModNoteDefinition,
    },
    {
        cname: 'newmodmail',
        constructor: NewModmail,
        definition: NewModmailDefinition,
    },
    {
        cname: 'flair',
        constructor: Flair,
        definition: FlairDefinition,
    },
    {
        cname: 'graphql',
        constructor: GraphQL,
        definition: GraphQLDefinition,
    },
    {
        cname: 'linksandcomments',
        constructor: LinksAndComments,
        definition: LinksAndCommentsDefinition,
    },
    {
        cname: 'moderation',
        constructor: Moderation,
        definition: ModerationDefinition,
    },
    {
        cname: 'privatemessages',
        constructor: PrivateMessages,
        definition: PrivateMessagesDefinition,
    },
    {
        cname: 'subreddits',
        constructor: Subreddits,
        definition: SubredditsDefinition,
    },
    {
        cname: 'users',
        constructor: Users,
        definition: UsersDefinition,
    },
    {
        cname: 'widgets',
        constructor: Widgets,
        definition: WidgetsDefinition,
    },
    {
        cname: 'wiki',
        constructor: Wiki,
        definition: WikiDefinition,
    },
];
const httpClient = getHttpClient();
// The Reddit API surface is an absolute unit,
// so we separate the methods into categories
// based on the classification in the reddit
// API docs: https://www.reddit.com/dev/api
const clients = [];
const defs = [];
for (const cat of apiCategories) {
    const hostname = childHostname(cat.cname, { hostname: dispatcher.hostname });
    const client = new cat.constructor(httpClient);
    clients.push(client);
    defs.push(cat.definition);
    // DEPRECATED!  This is for backwards compatibility with old clients.
    const server = EnvelopeServerBuilder.build(hostname, [cat.definition], client);
    dispatcher.bind(server);
}
function combine(...instances) {
    const combined = instances.shift();
    for (const _instance of instances) {
        const instance = _instance;
        // For each property of the instance
        for (const prop of Object.getOwnPropertyNames(Object.getPrototypeOf(instance))) {
            // If the property is a function (and not the constructor)
            if (typeof instance[prop] === 'function' && prop !== 'constructor') {
                // Add the method to the Combined class prototype
                combined[prop] = instance[prop];
            }
        }
    }
    return combined;
}
// Make a combined client for all categories, and put it at the root.  This is for
// future compatibility with the idea that we will not allow workers to have multiple
// hostnames and e.g. the privatemessages.* prefix will go away.
//
// See the `privatemessages.spec.ts` test for an example of how to test this works.
const combined = combine(...clients);
const root = EnvelopeServerBuilder.build(dispatcher.hostname, defs, combined);
dispatcher.bind(root);
Log.verbose(`${self.name} ready.`);
// All categories can use the same http client
// since the client is stateless
function getHttpClient() {
    const rootHostname = self.name.split('.').at(-1);
    const client = EnvelopeClientBuilder.build(resolvePluginHostname('http', { hostname: rootHostname }), [HTTPDefinition]);
    dispatcher.bind(client);
    return client;
}
