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 _Post_id, _Post_authorId, _Post_authorName, _Post_createdAt, _Post_subredditId, _Post_subredditName, _Post_permalink, _Post_title, _Post_body, _Post_bodyHtml, _Post_url, _Post_score, _Post_numberOfComments, _Post_numberOfReports, _Post_thumbnail, _Post_approved, _Post_approvedAtUtc, _Post_bannedAtUtc, _Post_spam, _Post_stickied, _Post_removed, _Post_removedBy, _Post_removedByCategory, _Post_archived, _Post_edited, _Post_locked, _Post_nsfw, _Post_quarantined, _Post_spoiler, _Post_hidden, _Post_ignoringReports, _Post_distinguishedBy, _Post_flair, _Post_secureMedia, _Post_modReportReasons, _Post_userReportReasons, _Post_metadata;
import { Block, CustomPostDefinition, Definition, UIEventHandlerDefinition, UIResponse, } from '@devvit/protos';
import { LinkedBundle } from '@devvit/protos/types/devvit/runtime/bundle.js';
import { assertNonNull } from '@devvit/shared-types/NonNull.js';
import { RichTextBuilder } from '@devvit/shared-types/richtext/RichTextBuilder.js';
import { asT2ID, asT3ID, asT5ID, isT3ID } from '@devvit/shared-types/tid.js';
import { fromByteArray, toByteArray } from 'base64-js';
import { Devvit } from '../../../devvit/Devvit.js';
import { BlocksReconciler } from '../../../devvit/internals/blocks/BlocksReconciler.js';
import { BlocksHandler } from '../../../devvit/internals/blocks/handler/BlocksHandler.js';
import { GraphQL } from '../graphql/GraphQL.js';
import { makeGettersEnumerable } from '../helpers/makeGettersEnumerable.js';
import { richtextToString } from '../helpers/richtextToString.js';
import { getCustomPostRichTextFallback } from '../helpers/textFallbackToRichtext.js';
import { Comment } from './Comment.js';
import { Listing } from './Listing.js';
import { ModNote } from './ModNote.js';
import { User } from './User.js';
export class Post {
    /**
     * @internal
     */
    constructor(data, metadata) {
        _Post_id.set(this, void 0);
        _Post_authorId.set(this, void 0);
        _Post_authorName.set(this, void 0);
        _Post_createdAt.set(this, void 0);
        _Post_subredditId.set(this, void 0);
        _Post_subredditName.set(this, void 0);
        _Post_permalink.set(this, void 0);
        _Post_title.set(this, void 0);
        _Post_body.set(this, void 0);
        _Post_bodyHtml.set(this, void 0);
        _Post_url.set(this, void 0);
        _Post_score.set(this, void 0);
        _Post_numberOfComments.set(this, void 0);
        _Post_numberOfReports.set(this, void 0);
        _Post_thumbnail.set(this, void 0);
        _Post_approved.set(this, void 0);
        _Post_approvedAtUtc.set(this, void 0);
        _Post_bannedAtUtc.set(this, void 0);
        _Post_spam.set(this, void 0);
        _Post_stickied.set(this, void 0);
        _Post_removed.set(this, void 0);
        _Post_removedBy.set(this, void 0);
        _Post_removedByCategory.set(this, void 0);
        _Post_archived.set(this, void 0);
        _Post_edited.set(this, void 0);
        _Post_locked.set(this, void 0);
        _Post_nsfw.set(this, void 0);
        _Post_quarantined.set(this, void 0);
        _Post_spoiler.set(this, void 0);
        _Post_hidden.set(this, void 0);
        _Post_ignoringReports.set(this, void 0);
        _Post_distinguishedBy.set(this, void 0);
        _Post_flair.set(this, void 0);
        _Post_secureMedia.set(this, void 0);
        _Post_modReportReasons.set(this, void 0);
        _Post_userReportReasons.set(this, void 0);
        _Post_metadata.set(this, void 0);
        makeGettersEnumerable(this);
        assertNonNull(data.id, 'Post is missing id');
        assertNonNull(data.title, 'Post is missing title');
        assertNonNull(data.createdUtc, 'Post is missing created date');
        assertNonNull(data.author, 'Post is missing author name');
        assertNonNull(data.subreddit, 'Post is missing subreddit name');
        assertNonNull(data.subredditId, 'Post is missing subreddit id');
        assertNonNull(data.url, 'Post is missing url');
        assertNonNull(data.permalink, 'Post is missing permalink');
        __classPrivateFieldSet(this, _Post_id, asT3ID(`t3_${data.id}`), "f");
        __classPrivateFieldSet(this, _Post_authorName, data.author, "f");
        __classPrivateFieldSet(this, _Post_authorId, data.authorFullname ? asT2ID(data.authorFullname) : undefined, "f");
        __classPrivateFieldSet(this, _Post_subredditId, asT5ID(data.subredditId), "f");
        __classPrivateFieldSet(this, _Post_subredditName, data.subreddit, "f");
        __classPrivateFieldSet(this, _Post_score, data.score ?? 0, "f");
        __classPrivateFieldSet(this, _Post_numberOfComments, data.numComments ?? 0, "f");
        __classPrivateFieldSet(this, _Post_numberOfReports, data.numReports ?? 0, "f");
        const createdAt = new Date(0);
        createdAt.setUTCSeconds(data.createdUtc);
        __classPrivateFieldSet(this, _Post_createdAt, createdAt, "f");
        __classPrivateFieldSet(this, _Post_title, data.title, "f");
        __classPrivateFieldSet(this, _Post_body, data.selftext, "f");
        __classPrivateFieldSet(this, _Post_bodyHtml, data.selftextHtml, "f");
        __classPrivateFieldSet(this, _Post_url, data.url, "f");
        __classPrivateFieldSet(this, _Post_permalink, data.permalink, "f");
        if (data.thumbnail &&
            data.thumbnail !== 'self' &&
            data.thumbnail !== 'nsfw' &&
            data.thumbnailHeight != null &&
            data.thumbnailWidth != null) {
            __classPrivateFieldSet(this, _Post_thumbnail, {
                url: data.thumbnail,
                height: data.thumbnailHeight,
                width: data.thumbnailWidth,
            }, "f");
        }
        __classPrivateFieldSet(this, _Post_approved, data.approved ?? false, "f");
        __classPrivateFieldSet(this, _Post_approvedAtUtc, data.approvedAtUtc ?? 0, "f");
        __classPrivateFieldSet(this, _Post_bannedAtUtc, data.bannedAtUtc ?? 0, "f");
        __classPrivateFieldSet(this, _Post_removed, data.removed ?? false, "f");
        __classPrivateFieldSet(this, _Post_removedBy, data.removedBy, "f");
        __classPrivateFieldSet(this, _Post_removedByCategory, data.removedByCategory, "f");
        __classPrivateFieldSet(this, _Post_spam, data.spam ?? false, "f");
        __classPrivateFieldSet(this, _Post_stickied, data.stickied ?? false, "f");
        __classPrivateFieldSet(this, _Post_archived, data.archived ?? false, "f");
        __classPrivateFieldSet(this, _Post_edited, data.edited ?? false, "f");
        __classPrivateFieldSet(this, _Post_locked, data.locked ?? false, "f");
        __classPrivateFieldSet(this, _Post_nsfw, data.over18 ?? false, "f");
        __classPrivateFieldSet(this, _Post_quarantined, data.quarantine ?? false, "f");
        __classPrivateFieldSet(this, _Post_spoiler, data.spoiler, "f");
        __classPrivateFieldSet(this, _Post_hidden, data.hidden ?? false, "f");
        __classPrivateFieldSet(this, _Post_ignoringReports, data.ignoreReports ?? false, "f");
        __classPrivateFieldSet(this, _Post_distinguishedBy, data.distinguished, "f");
        __classPrivateFieldSet(this, _Post_secureMedia, data.secureMedia, "f");
        __classPrivateFieldSet(this, _Post_modReportReasons, (data.modReports ?? []).map(([reason]) => reason), "f");
        __classPrivateFieldSet(this, _Post_userReportReasons, (data.userReports ?? []).map(([reason]) => reason), "f");
        __classPrivateFieldSet(this, _Post_metadata, metadata, "f");
        if (data.linkFlairBackgroundColor ||
            data.linkFlairCssClass ||
            data.linkFlairText ||
            data.linkFlairType ||
            data.linkFlairTemplateId ||
            data.linkFlairRichtext ||
            data.linkFlairTextColor) {
            __classPrivateFieldSet(this, _Post_flair, {
                backgroundColor: data.linkFlairBackgroundColor,
                cssClass: data.linkFlairCssClass,
                text: data.linkFlairText,
                type: data.linkFlairType,
                templateId: data.linkFlairTemplateId,
                // Map linkFlairRichtext[] into the objects with more user-friendly property names
                richtext: (data.linkFlairRichtext ?? []).map(({ e, t, a, u }) => ({
                    elementType: e,
                    text: t,
                    emojiRef: a,
                    url: u,
                })),
                textColor: data.linkFlairTextColor,
            }, "f");
        }
    }
    get id() {
        return __classPrivateFieldGet(this, _Post_id, "f");
    }
    get authorId() {
        return __classPrivateFieldGet(this, _Post_authorId, "f");
    }
    get authorName() {
        return __classPrivateFieldGet(this, _Post_authorName, "f");
    }
    get subredditId() {
        return __classPrivateFieldGet(this, _Post_subredditId, "f");
    }
    get subredditName() {
        return __classPrivateFieldGet(this, _Post_subredditName, "f");
    }
    get permalink() {
        return __classPrivateFieldGet(this, _Post_permalink, "f");
    }
    get title() {
        return __classPrivateFieldGet(this, _Post_title, "f");
    }
    get body() {
        return __classPrivateFieldGet(this, _Post_body, "f");
    }
    get bodyHtml() {
        return __classPrivateFieldGet(this, _Post_bodyHtml, "f");
    }
    get url() {
        return __classPrivateFieldGet(this, _Post_url, "f");
    }
    get thumbnail() {
        return __classPrivateFieldGet(this, _Post_thumbnail, "f");
    }
    get createdAt() {
        return __classPrivateFieldGet(this, _Post_createdAt, "f");
    }
    get score() {
        return __classPrivateFieldGet(this, _Post_score, "f");
    }
    get numberOfComments() {
        return __classPrivateFieldGet(this, _Post_numberOfComments, "f");
    }
    get numberOfReports() {
        return __classPrivateFieldGet(this, _Post_numberOfReports, "f");
    }
    get approved() {
        return __classPrivateFieldGet(this, _Post_approved, "f");
    }
    get approvedAtUtc() {
        return __classPrivateFieldGet(this, _Post_approvedAtUtc, "f");
    }
    get bannedAtUtc() {
        return __classPrivateFieldGet(this, _Post_bannedAtUtc, "f");
    }
    get spam() {
        return __classPrivateFieldGet(this, _Post_spam, "f");
    }
    get stickied() {
        return __classPrivateFieldGet(this, _Post_stickied, "f");
    }
    get removed() {
        return __classPrivateFieldGet(this, _Post_removed, "f");
    }
    /**
     * Who removed this object (username)
     */
    get removedBy() {
        return __classPrivateFieldGet(this, _Post_removedBy, "f");
    }
    /**
     * who/what removed this object. It will return one of the following:
     * - "anti_evil_ops": object is removed by a aeops member
     * - "author": object is removed by author of the post
     * - "automod_filtered": object is filtered by automod
     * - "community_ops": object is removed by a community team member
     * - "content_takedown": object is removed due to content violation
     * - "copyright_takedown": object is removed due to copyright violation
     * - "deleted": object is deleted
     * - "moderator": object is removed by a mod of the sub
     * - "reddit": object is removed by anyone else
     * - undefined: object is not removed
     */
    get removedByCategory() {
        return __classPrivateFieldGet(this, _Post_removedByCategory, "f");
    }
    get archived() {
        return __classPrivateFieldGet(this, _Post_archived, "f");
    }
    get edited() {
        return __classPrivateFieldGet(this, _Post_edited, "f");
    }
    get locked() {
        return __classPrivateFieldGet(this, _Post_locked, "f");
    }
    get nsfw() {
        return __classPrivateFieldGet(this, _Post_nsfw, "f");
    }
    get quarantined() {
        return __classPrivateFieldGet(this, _Post_quarantined, "f");
    }
    get spoiler() {
        return __classPrivateFieldGet(this, _Post_spoiler, "f");
    }
    get hidden() {
        return __classPrivateFieldGet(this, _Post_hidden, "f");
    }
    get ignoringReports() {
        return __classPrivateFieldGet(this, _Post_ignoringReports, "f");
    }
    get distinguishedBy() {
        return __classPrivateFieldGet(this, _Post_distinguishedBy, "f");
    }
    get comments() {
        return Comment.getComments({
            postId: this.id,
        }, __classPrivateFieldGet(this, _Post_metadata, "f"));
    }
    get flair() {
        return __classPrivateFieldGet(this, _Post_flair, "f");
    }
    get secureMedia() {
        return __classPrivateFieldGet(this, _Post_secureMedia, "f");
    }
    get userReportReasons() {
        return __classPrivateFieldGet(this, _Post_userReportReasons, "f");
    }
    get modReportReasons() {
        return __classPrivateFieldGet(this, _Post_modReportReasons, "f");
    }
    toJSON() {
        return {
            id: this.id,
            authorId: this.authorId,
            authorName: this.authorName,
            subredditId: this.subredditId,
            subredditName: this.subredditName,
            permalink: this.permalink,
            title: this.title,
            body: this.body,
            bodyHtml: this.bodyHtml,
            url: this.url,
            thumbnail: this.thumbnail,
            score: this.score,
            numberOfComments: this.numberOfComments,
            numberOfReports: this.numberOfReports,
            createdAt: this.createdAt,
            approved: this.approved,
            spam: this.spam,
            stickied: this.stickied,
            removed: this.removed,
            removedBy: __classPrivateFieldGet(this, _Post_removedBy, "f"),
            removedByCategory: __classPrivateFieldGet(this, _Post_removedByCategory, "f"),
            archived: this.archived,
            edited: this.edited,
            locked: this.locked,
            nsfw: this.nsfw,
            quarantined: this.quarantined,
            spoiler: this.spoiler,
            hidden: this.hidden,
            ignoringReports: this.ignoringReports,
            distinguishedBy: this.distinguishedBy,
            flair: this.flair,
            secureMedia: this.secureMedia,
            modReportReasons: __classPrivateFieldGet(this, _Post_modReportReasons, "f"),
            userReportReasons: __classPrivateFieldGet(this, _Post_userReportReasons, "f"),
        };
    }
    isApproved() {
        return __classPrivateFieldGet(this, _Post_approved, "f");
    }
    isSpam() {
        return __classPrivateFieldGet(this, _Post_spam, "f");
    }
    isStickied() {
        return __classPrivateFieldGet(this, _Post_stickied, "f");
    }
    isRemoved() {
        return __classPrivateFieldGet(this, _Post_removed, "f");
    }
    isArchived() {
        return __classPrivateFieldGet(this, _Post_archived, "f");
    }
    isEdited() {
        return __classPrivateFieldGet(this, _Post_edited, "f");
    }
    isLocked() {
        return __classPrivateFieldGet(this, _Post_locked, "f");
    }
    isNsfw() {
        return __classPrivateFieldGet(this, _Post_nsfw, "f");
    }
    isQuarantined() {
        return __classPrivateFieldGet(this, _Post_quarantined, "f");
    }
    isSpoiler() {
        return __classPrivateFieldGet(this, _Post_spoiler, "f");
    }
    isHidden() {
        return __classPrivateFieldGet(this, _Post_hidden, "f");
    }
    isIgnoringReports() {
        return __classPrivateFieldGet(this, _Post_ignoringReports, "f");
    }
    isDistinguishedBy() {
        return __classPrivateFieldGet(this, _Post_distinguishedBy, "f");
    }
    async edit(options) {
        const newPost = await Post.edit({
            id: this.id,
            ...options,
        }, __classPrivateFieldGet(this, _Post_metadata, "f"));
        __classPrivateFieldSet(this, _Post_body, newPost.body, "f");
        __classPrivateFieldSet(this, _Post_edited, newPost.edited, "f");
    }
    /**
     * Set the suggested sort for comments on a Post.
     *
     * @throws {Error} Throws an error if the suggested sort could not be set.
     * @example
     * ```ts
     * const post = await reddit.getPostById(context.postId);
     * await post.setSuggestedCommentSort("NEW");
     * ```
     */
    async setSuggestedCommentSort(suggestedSort) {
        await Post.setSuggestedCommentSort({ id: this.id, subredditId: __classPrivateFieldGet(this, _Post_subredditId, "f"), suggestedSort }, __classPrivateFieldGet(this, _Post_metadata, "f"));
    }
    /**
     * Set a lightweight UI that shows while the custom post renders
     *
     * @param {JSX.ComponentFunction} ui - A JSX component function that returns a simple ui to be rendered.
     * @throws {Error} Throws an error if the preview could not be set.
     * @example
     * ```ts
     * const preview = (
     *   <vstack height="100%" width="100%" alignment="middle center">
     *     <text size="large">An updated preview!</text>
     *   </vstack>
     * );
     * const post = await reddit.getPostById(context.postId);
     * await post.setCustomPostPreview(() => preview);
     * ```
     */
    async setCustomPostPreview(ui) {
        const newPost = await Post.setCustomPostPreview({
            id: this.id,
            body: this.body,
            ui,
        }, __classPrivateFieldGet(this, _Post_metadata, "f"));
        __classPrivateFieldSet(this, _Post_body, newPost.body, "f");
        __classPrivateFieldSet(this, _Post_edited, newPost.edited, "f");
    }
    /**
     * Set a text fallback for the custom post
     *
     * @param {CustomPostTextFallbackOptions} options - A text or a richtext to render in a fallback
     * @throws {Error} Throws an error if the fallback could not be set.
     * @example
     * ```ts
     * // from a menu action, form, scheduler, trigger, custom post click event, etc
     * const newTextFallback = { text: 'This is an updated text fallback' };
     * const post = await context.reddit.getPostById(context.postId);
     * await post.setTextFallback(newTextFallback);
     * ```
     */
    async setTextFallback(options) {
        const newPost = await Post.setTextFallback(options, this.id, __classPrivateFieldGet(this, _Post_metadata, "f"));
        __classPrivateFieldSet(this, _Post_body, newPost.body, "f");
        __classPrivateFieldSet(this, _Post_edited, newPost.edited, "f");
    }
    async addComment(options) {
        return Comment.submit({
            id: this.id,
            ...options,
        }, __classPrivateFieldGet(this, _Post_metadata, "f"));
    }
    async delete() {
        return Post.delete(this.id, __classPrivateFieldGet(this, _Post_metadata, "f"));
    }
    async approve() {
        await Post.approve(this.id, __classPrivateFieldGet(this, _Post_metadata, "f"));
        __classPrivateFieldSet(this, _Post_approved, true, "f");
        __classPrivateFieldSet(this, _Post_removed, false, "f");
    }
    async remove(isSpam = false) {
        await Post.remove(this.id, isSpam, __classPrivateFieldGet(this, _Post_metadata, "f"));
        __classPrivateFieldSet(this, _Post_removed, true, "f");
        __classPrivateFieldSet(this, _Post_spam, isSpam, "f");
        __classPrivateFieldSet(this, _Post_approved, false, "f");
    }
    async lock() {
        await Post.lock(this.id, __classPrivateFieldGet(this, _Post_metadata, "f"));
        __classPrivateFieldSet(this, _Post_locked, true, "f");
    }
    async unlock() {
        await Post.unlock(this.id, __classPrivateFieldGet(this, _Post_metadata, "f"));
        __classPrivateFieldSet(this, _Post_locked, false, "f");
    }
    async hide() {
        await Post.hide(this.id, __classPrivateFieldGet(this, _Post_metadata, "f"));
        __classPrivateFieldSet(this, _Post_hidden, true, "f");
    }
    async unhide() {
        await Post.unhide(this.id, __classPrivateFieldGet(this, _Post_metadata, "f"));
        __classPrivateFieldSet(this, _Post_hidden, false, "f");
    }
    async markAsNsfw() {
        await Post.markAsNsfw(this.id, __classPrivateFieldGet(this, _Post_metadata, "f"));
        __classPrivateFieldSet(this, _Post_nsfw, true, "f");
    }
    async unmarkAsNsfw() {
        await Post.unmarkAsNsfw(this.id, __classPrivateFieldGet(this, _Post_metadata, "f"));
        __classPrivateFieldSet(this, _Post_nsfw, false, "f");
    }
    async markAsSpoiler() {
        await Post.markAsSpoiler(this.id, __classPrivateFieldGet(this, _Post_metadata, "f"));
        __classPrivateFieldSet(this, _Post_spoiler, true, "f");
    }
    async unmarkAsSpoiler() {
        await Post.unmarkAsSpoiler(this.id, __classPrivateFieldGet(this, _Post_metadata, "f"));
        __classPrivateFieldSet(this, _Post_spoiler, false, "f");
    }
    async sticky(position) {
        await Post.sticky(this.id, position, __classPrivateFieldGet(this, _Post_metadata, "f"));
    }
    async unsticky() {
        await Post.unsticky(this.id, __classPrivateFieldGet(this, _Post_metadata, "f"));
    }
    async distinguish() {
        const { distinguishedBy } = await Post.distinguish(this.id, false, __classPrivateFieldGet(this, _Post_metadata, "f"));
        __classPrivateFieldSet(this, _Post_distinguishedBy, distinguishedBy, "f");
    }
    async distinguishAsAdmin() {
        const { distinguishedBy } = await Post.distinguish(this.id, true, __classPrivateFieldGet(this, _Post_metadata, "f"));
        __classPrivateFieldSet(this, _Post_distinguishedBy, distinguishedBy, "f");
    }
    async undistinguish() {
        const { distinguishedBy } = await Post.undistinguish(this.id, __classPrivateFieldGet(this, _Post_metadata, "f"));
        __classPrivateFieldSet(this, _Post_distinguishedBy, distinguishedBy, "f");
    }
    async ignoreReports() {
        await Post.ignoreReports(this.id, __classPrivateFieldGet(this, _Post_metadata, "f"));
        __classPrivateFieldSet(this, _Post_ignoringReports, true, "f");
    }
    async unignoreReports() {
        await Post.unignoreReports(this.id, __classPrivateFieldGet(this, _Post_metadata, "f"));
        __classPrivateFieldSet(this, _Post_ignoringReports, false, "f");
    }
    async getAuthor() {
        return User.getByUsername(__classPrivateFieldGet(this, _Post_authorName, "f"), __classPrivateFieldGet(this, _Post_metadata, "f"));
    }
    async crosspost(options) {
        return Post.crosspost({
            ...options,
            postId: this.id,
        }, __classPrivateFieldGet(this, _Post_metadata, "f"));
    }
    /**
     * Add a mod note for why the post was removed
     *
     * @param options.reasonId id of a Removal Reason - you can leave this as an empty string if you don't have one
     * @param options.modNote the reason for removal (maximum 100 characters) (optional)
     * @returns
     */
    addRemovalNote(options) {
        return ModNote.addRemovalNote({ itemIds: [__classPrivateFieldGet(this, _Post_id, "f")], ...options }, __classPrivateFieldGet(this, _Post_metadata, "f"));
    }
    // TODO: flair methods
    /** @internal */
    static async getById(id, metadata) {
        const client = Devvit.redditAPIPlugins.LinksAndComments;
        const postId = isT3ID(id) ? id : `t3_${id}`;
        const response = await client.Info({
            subreddits: [],
            thingIds: [postId],
        }, metadata);
        if (!response.data?.children?.length) {
            throw new Error('could not find post');
        }
        const postData = response.data.children[0];
        if (!postData?.data) {
            throw new Error('could not find post');
        }
        return new Post(postData.data, metadata);
    }
    /** @internal */
    static async submit(options, metadata) {
        const client = Devvit.redditAPIPlugins.LinksAndComments;
        let response;
        if ('preview' in options) {
            assertNonNull(metadata, 'Missing metadata in `SubmitPostOptions`');
            const reconciler = new BlocksReconciler(() => options.preview, undefined, {}, metadata, undefined);
            const previewBlock = await reconciler.buildBlocksUI();
            const encodedCached = Block.encode(previewBlock).finish();
            const { textFallback, ...sanitizedOptions } = options;
            const richtextFallback = textFallback ? getCustomPostRichTextFallback(textFallback) : '';
            const submitRequest = {
                kind: 'custom',
                sr: options.subredditName,
                richtextJson: fromByteArray(encodedCached),
                richtextFallback,
                ...sanitizedOptions,
            };
            response = await client.SubmitCustomPost(submitRequest, metadata);
        }
        else {
            response = await client.Submit({
                kind: 'kind' in options ? options.kind : 'url' in options ? 'link' : 'self',
                sr: options.subredditName,
                richtextJson: 'richtext' in options ? richtextToString(options.richtext) : undefined,
                ...options,
            }, metadata);
        }
        // Post Id might not be present as image/video post creation can happen asynchronously
        const isAllowedMediaType = 'kind' in options && ['image', 'video', 'videogif'].includes(options.kind);
        if (isAllowedMediaType && !response.json?.data?.id && 'url' in options) {
            throw new Error(`Post of ${options.kind} type with ${options.url} is being created asynchronously and should be updated in the subreddit soon.`);
        }
        if (!response.json?.data?.id || response.json?.errors?.length) {
            throw new Error(`failed to submit post - either post ID is empty or request failed with errors: ${response.json?.errors}`);
        }
        return Post.getById(`t3_${response.json.data.id}`, metadata);
    }
    /** @internal */
    static async crosspost(options, metadata) {
        const client = Devvit.redditAPIPlugins.LinksAndComments;
        const { postId, subredditName, ...rest } = options;
        const response = await client.Submit({
            kind: 'crosspost',
            sr: subredditName,
            crosspostFullname: asT3ID(postId),
            ...rest,
        }, metadata);
        if (!response.json?.data?.id || response.json?.errors?.length) {
            throw new Error('failed to crosspost post');
        }
        return Post.getById(`t3_${response.json.data.id}`, metadata);
    }
    /** @internal */
    static async edit(options, metadata) {
        const client = Devvit.redditAPIPlugins.LinksAndComments;
        const { id } = options;
        let richtextString;
        if ('richtext' in options) {
            richtextString = richtextToString(options.richtext);
        }
        const response = await client.EditUserText({
            thingId: id,
            text: 'text' in options ? options.text : '',
            richtextJson: richtextString,
        }, metadata);
        if (response.json?.errors?.length) {
            throw new Error('Failed to edit post');
        }
        // The LinksAndComments.EditUserText response is wrong and assumes that
        // the API is only used to for comments so we fetch the new post here.
        return Post.getById(id, metadata);
    }
    /** @internal */
    static async setSuggestedCommentSort(options, metadata) {
        const operationName = 'SetSuggestedSort';
        const persistedQueryHash = 'cf6052acc7fefaa65b710625b81dba8041f258313aafe9730e2a3dc855e5d10d';
        const response = await GraphQL.query(operationName, persistedQueryHash, {
            input: {
                subredditId: options.subredditId,
                postId: options.id,
                sort: options.suggestedSort,
            },
        }, metadata);
        if (!response.data?.setSuggestedSort?.ok) {
            throw new Error('Failed to set suggested sort');
        }
    }
    /** @internal */
    static async setCustomPostPreview(options, metadata) {
        if (!metadata) {
            throw new Error('Failed to set custom post preview. Metadata not found');
        }
        // Get skinny bundle from post
        const bundleMatches = new RegExp(/DX_Bundle:\n\n {4}(?<bundle>[^\n]*)/g).exec(options.body ?? '');
        if (!bundleMatches?.groups?.['bundle']) {
            throw new Error(`Failed to set custom post preview. Couldn't find bundle in post ${options.id}`);
        }
        const origBundle = toByteArray(bundleMatches.groups['bundle']);
        const myBundle = LinkedBundle.decode(origBundle);
        // Ensure we have all the correct definitions
        myBundle.provides = [CustomPostDefinition, UIEventHandlerDefinition].map((d) => Definition.toSerializable(d));
        const newBundle = fromByteArray(LinkedBundle.encode(myBundle).finish());
        // Get fallback text from post, if it exists
        const fallbackMatches = new RegExp(/DX_RichtextFallback:\n\n {4}(?<fallback>[^\n]*)/g).exec(options.body ?? '');
        const textFallback = fallbackMatches?.groups?.['fallback'];
        const handler = new BlocksHandler(options.ui);
        const handlerResponse = UIResponse.fromJSON(await handler.handle({ events: [] }, metadata));
        const block = handlerResponse.blocks;
        const cached = fromByteArray(Block.encode(block).finish());
        const postRTJson = new RichTextBuilder()
            .heading({ level: 1 }, (h) => h.rawText('DX_Bundle:'))
            .codeBlock({ language: '' }, (c) => {
            c.rawText(newBundle);
        })
            .heading({ level: 1 }, (h) => h.rawText('DX_Config:'))
            .codeBlock({ language: '' }, (c) => {
            c.rawText('EgA=');
        })
            .heading({ level: 1 }, (h) => h.rawText('DX_Cached:'))
            .codeBlock({ language: '' }, (c) => {
            c.rawText(cached);
        });
        if (textFallback) {
            postRTJson
                .heading({ level: 1 }, (h) => h.rawText('DX_RichtextFallback:'))
                .codeBlock({ language: '' }, (c) => {
                c.rawText(textFallback);
            });
        }
        const operationName = 'UpdatePost';
        const persistedQueryHash = 'ccc5f1da31a8d8c518b6607e81c2903a46f922cb6562c8b47fcc8988f0611360';
        const response = await GraphQL.query(operationName, persistedQueryHash, {
            input: {
                postId: options.id,
                content: {
                    richText: postRTJson.build(),
                },
            },
        }, metadata);
        if (!response.data?.updatePost?.ok) {
            throw new Error('Failed to set custom post preview');
        }
        return Post.getById(options.id, metadata);
    }
    /** @internal */
    static async setTextFallback(options, postId, metadata) {
        if (!('text' in options) && !('richtext' in options)) {
            throw new Error(`No text fallback provided for post ${postId}.`);
        }
        const client = Devvit.redditAPIPlugins.LinksAndComments;
        const richtextFallback = getCustomPostRichTextFallback(options);
        const response = await client.EditCustomPost({
            thingId: postId,
            richtextFallback,
        }, metadata);
        if (response.json?.errors?.length) {
            throw new Error('Failed to set post text fallback');
        }
        return Post.getById(postId, metadata);
    }
    /** @internal */
    static async delete(id, metadata) {
        const client = Devvit.redditAPIPlugins.LinksAndComments;
        await client.Del({
            id,
        }, metadata);
    }
    /** @internal */
    static async approve(id, metadata) {
        const client = Devvit.redditAPIPlugins.Moderation;
        await client.Approve({
            id,
        }, metadata);
    }
    /** @internal */
    static async remove(id, isSpam = false, metadata) {
        const client = Devvit.redditAPIPlugins.Moderation;
        await client.Remove({
            id,
            spam: isSpam,
        }, metadata);
    }
    /** @internal */
    static async hide(id, metadata) {
        const client = Devvit.redditAPIPlugins.LinksAndComments;
        await client.Hide({
            id,
        }, metadata);
    }
    /** @internal */
    static async unhide(id, metadata) {
        const client = Devvit.redditAPIPlugins.LinksAndComments;
        await client.Unhide({
            id,
        }, metadata);
    }
    /** @internal */
    static async markAsNsfw(id, metadata) {
        const client = Devvit.redditAPIPlugins.LinksAndComments;
        await client.MarkNSFW({
            id,
        }, metadata);
    }
    /** @internal */
    static async unmarkAsNsfw(id, metadata) {
        const client = Devvit.redditAPIPlugins.LinksAndComments;
        await client.UnmarkNSFW({
            id,
        }, metadata);
    }
    /** @internal */
    static async markAsSpoiler(id, metadata) {
        const client = Devvit.redditAPIPlugins.LinksAndComments;
        await client.Spoiler({
            id,
        }, metadata);
    }
    /** @internal */
    static async unmarkAsSpoiler(id, metadata) {
        const client = Devvit.redditAPIPlugins.LinksAndComments;
        await client.Unspoiler({
            id,
        }, metadata);
    }
    /** @internal */
    static async sticky(id, position, metadata) {
        const client = Devvit.redditAPIPlugins.LinksAndComments;
        await client.SetSubredditSticky({
            id,
            state: true,
            num: position,
        }, metadata);
    }
    /** @internal */
    static async unsticky(id, metadata) {
        const client = Devvit.redditAPIPlugins.LinksAndComments;
        await client.SetSubredditSticky({
            id,
            state: false,
        }, metadata);
    }
    /** @internal */
    static async lock(id, metadata) {
        const client = Devvit.redditAPIPlugins.LinksAndComments;
        await client.Lock({
            id,
        }, metadata);
    }
    /** @internal */
    static async unlock(id, metadata) {
        const client = Devvit.redditAPIPlugins.LinksAndComments;
        await client.Unlock({
            id,
        }, metadata);
    }
    /** @internal */
    static async distinguish(id, asAdmin, metadata) {
        const client = Devvit.redditAPIPlugins.Moderation;
        const response = await client.Distinguish({
            id,
            how: asAdmin ? 'admin' : 'yes',
            sticky: false,
        }, metadata);
        const post = response.json?.data?.things?.[0]?.data;
        assertNonNull(post);
        return {
            distinguishedBy: post.distinguished,
        };
    }
    /** @internal */
    static async undistinguish(id, metadata) {
        const client = Devvit.redditAPIPlugins.Moderation;
        const response = await client.Distinguish({
            id,
            how: 'no',
            sticky: false,
        }, metadata);
        const post = response.json?.data?.things?.[0]?.data;
        assertNonNull(post);
        return {
            distinguishedBy: post.distinguished,
        };
    }
    /** @internal */
    static async ignoreReports(id, metadata) {
        const client = Devvit.redditAPIPlugins.Moderation;
        await client.IgnoreReports({
            id,
        }, metadata);
    }
    /** @internal */
    static async unignoreReports(id, metadata) {
        const client = Devvit.redditAPIPlugins.Moderation;
        await client.UnignoreReports({
            id,
        }, metadata);
    }
    /** @internal */
    static getControversialPosts(options = {}, metadata) {
        return this.getSortedPosts({
            ...options,
            sort: 'controversial',
        }, metadata);
    }
    /** @internal */
    static getTopPosts(options = {}, metadata) {
        return this.getSortedPosts({
            ...options,
            sort: 'top',
        }, metadata);
    }
    /** @internal */
    static getSortedPosts(options, metadata) {
        const client = Devvit.redditAPIPlugins.Listings;
        return new Listing({
            hasMore: true,
            before: options.before,
            after: options.after,
            pageSize: options.pageSize,
            limit: options.limit,
            fetch: async (fetchOptions) => {
                const response = await client.Sort({
                    show: 'all',
                    sort: options.sort,
                    t: options.timeframe,
                    subreddit: options.subredditName,
                    ...fetchOptions,
                }, metadata);
                return listingProtosToPosts(response, metadata);
            },
        });
    }
    /** @internal */
    static getHotPosts(options = {
        location: 'GLOBAL',
    }, metadata) {
        const client = Devvit.redditAPIPlugins.Listings;
        return new Listing({
            hasMore: true,
            before: options.before,
            after: options.after,
            pageSize: options.pageSize,
            limit: options.limit,
            fetch: async (fetchOptions) => {
                const response = await client.Hot({
                    g: options.location,
                    show: 'all',
                    subreddit: options.subredditName,
                    ...fetchOptions,
                }, metadata);
                return listingProtosToPosts(response, metadata);
            },
        });
    }
    /** @internal */
    static getNewPosts(options, metadata) {
        const client = Devvit.redditAPIPlugins.Listings;
        return new Listing({
            hasMore: true,
            before: options.before,
            after: options.after,
            pageSize: options.pageSize,
            limit: options.limit,
            fetch: async (fetchOptions) => {
                const response = await client.New({
                    show: 'all',
                    subreddit: options.subredditName,
                    ...fetchOptions,
                }, metadata);
                return listingProtosToPosts(response, metadata);
            },
        });
    }
    /** @internal */
    static getRisingPosts(options, metadata) {
        const client = Devvit.redditAPIPlugins.Listings;
        return new Listing({
            hasMore: true,
            before: options.before,
            after: options.after,
            pageSize: options.pageSize,
            limit: options.limit,
            fetch: async (fetchOptions) => {
                const response = await client.Rising({
                    show: 'all',
                    subreddit: options.subredditName,
                    ...fetchOptions,
                }, metadata);
                return listingProtosToPosts(response, metadata);
            },
        });
    }
    /** @internal */
    static getPostsByUser(options, metadata) {
        const client = Devvit.redditAPIPlugins.Users;
        return new Listing({
            hasMore: true,
            before: options.before,
            after: options.after,
            pageSize: options.pageSize,
            limit: options.limit,
            async fetch(fetchOptions) {
                const response = await client.UserWhere({
                    username: options.username,
                    where: 'submitted',
                    ...fetchOptions,
                }, metadata);
                return listingProtosToPosts(response, metadata);
            },
        });
    }
}
_Post_id = new WeakMap(), _Post_authorId = new WeakMap(), _Post_authorName = new WeakMap(), _Post_createdAt = new WeakMap(), _Post_subredditId = new WeakMap(), _Post_subredditName = new WeakMap(), _Post_permalink = new WeakMap(), _Post_title = new WeakMap(), _Post_body = new WeakMap(), _Post_bodyHtml = new WeakMap(), _Post_url = new WeakMap(), _Post_score = new WeakMap(), _Post_numberOfComments = new WeakMap(), _Post_numberOfReports = new WeakMap(), _Post_thumbnail = new WeakMap(), _Post_approved = new WeakMap(), _Post_approvedAtUtc = new WeakMap(), _Post_bannedAtUtc = new WeakMap(), _Post_spam = new WeakMap(), _Post_stickied = new WeakMap(), _Post_removed = new WeakMap(), _Post_removedBy = new WeakMap(), _Post_removedByCategory = new WeakMap(), _Post_archived = new WeakMap(), _Post_edited = new WeakMap(), _Post_locked = new WeakMap(), _Post_nsfw = new WeakMap(), _Post_quarantined = new WeakMap(), _Post_spoiler = new WeakMap(), _Post_hidden = new WeakMap(), _Post_ignoringReports = new WeakMap(), _Post_distinguishedBy = new WeakMap(), _Post_flair = new WeakMap(), _Post_secureMedia = new WeakMap(), _Post_modReportReasons = new WeakMap(), _Post_userReportReasons = new WeakMap(), _Post_metadata = new WeakMap();
function listingProtosToPosts(listingProto, metadata) {
    if (!listingProto.data?.children) {
        throw new Error('Listing response is missing children');
    }
    const children = listingProto.data.children.map((child) => new Post(child.data, metadata));
    return {
        children,
        before: listingProto.data.before,
        after: listingProto.data.after,
    };
}
