import { HEADINGS } from "../content/constants.js";
import { getSettings } from "../settings.js";
import { MarkdownRenderer, MarkdownSite } from "./markdown.js";
import { escapeText, getPrettyCodeSampleLanguage } from "./util.js";
export class MdxSite extends MarkdownSite {
    #compilerConfig;
    constructor(compilerConfig) {
        super();
        this.#compilerConfig = compilerConfig;
    }
    buildPagePath(...[slug, { appendIndex = false } = {}]) {
        return this.#compilerConfig.buildPagePath(slug, { appendIndex });
    }
    getRenderer(...[options]) {
        return new MdxRenderer({ ...options }, this.#compilerConfig);
    }
    processPageMetadata(pageMetadata) {
        this.#compilerConfig.postProcess?.(pageMetadata);
    }
}
class MdxRenderer extends MarkdownRenderer {
    // Mapping of import path to imported symbols
    #imports = new Map();
    #compilerConfig;
    #frontMatter;
    constructor(options, compilerConfig) {
        super(options);
        this.#compilerConfig = compilerConfig;
        if (options.frontMatter) {
            this.#frontMatter = compilerConfig.buildPagePreamble(options.frontMatter);
        }
    }
    #insertNamedImport(importPath, symbol) {
        if (!this.#imports.has(importPath)) {
            this.#imports.set(importPath, new Set());
        }
        this.#imports.get(importPath)?.add(symbol);
    }
    #insertComponentImport(symbol) {
        this.#insertNamedImport(this.#compilerConfig.componentPackageName, symbol);
    }
    #createComponentOpeningTag(symbol, props, { selfClosing }) {
        this.#insertComponentImport(symbol);
        function serializeProps(separator) {
            return Object.entries(props)
                .map(([key, value]) => {
                if (typeof value === "string") {
                    if (value.includes("\n")) {
                        return `${separator}${key}={\`${value}\`}`;
                    }
                    return `${separator}${key}="${value}"`;
                }
                else if (value !== undefined) {
                    return `${separator}${key}={${JSON.stringify(value)}}`;
                }
                else {
                    return "";
                }
            })
                .join("");
        }
        let serializedProps = serializeProps(" ");
        const isMultiline = serializedProps.length > 80;
        if (isMultiline) {
            serializedProps = serializeProps("\n  ");
        }
        return `<${symbol}${serializedProps}${selfClosing ? (isMultiline ? "\n/" : " /") : isMultiline ? "\n" : ""}>`;
    }
    #createComponentClosingTag(symbol) {
        return `</${symbol}>`;
    }
    #appendComponent(symbol, props, cb) {
        this.appendLine(this.#createComponentOpeningTag(symbol, props, {
            selfClosing: !cb,
        }));
        if (cb) {
            cb();
            this.appendLine(this.#createComponentClosingTag(symbol));
        }
    }
    #createComponent(symbol, props, cb) {
        if (cb) {
            return (this.#createComponentOpeningTag(symbol, props, {
                selfClosing: false,
            }) +
                cb() +
                this.#createComponentClosingTag(symbol));
        }
        else {
            return this.#createComponentOpeningTag(symbol, props, {
                selfClosing: true,
            });
        }
    }
    getIdSeparator() {
        return this.#compilerConfig.elementIdSeparator ?? "+";
    }
    render() {
        // Render the main content
        const { contents, metadata } = super.render();
        // If we have front matter, add it to the top of the file
        let frontMatter = this.#frontMatter ? this.#frontMatter + "\n" : "";
        // Add imports after front matter
        for (const [importPath, symbols] of this.#imports) {
            frontMatter += `import {\n  ${Array.from(symbols).sort().join(",\n  ")}\n} from "${importPath}";\n`;
        }
        // Add a blank line after front matter, if it exists
        if (frontMatter) {
            frontMatter += "\n";
        }
        // Return the final result
        return {
            contents: frontMatter + contents,
            metadata,
        };
    }
    createHeading(...[level, text, { escape = "markdown", id, append = true } = {},]) {
        let line = `${`#`.repeat(level)} ${escapeText(text, { escape })}`;
        if (id) {
            if (this.#compilerConfig.formatHeadingId) {
                line += ` ${this.#compilerConfig.formatHeadingId(id)}`;
            }
            else {
                line += ` \\{#${id}\\}`;
            }
        }
        if (append) {
            this.appendLine(line);
        }
        return line;
    }
    createCode(...[text, options]) {
        let line;
        if (options?.variant === "raw") {
            if (options.style === "inline") {
                line = `<code>${escapeText(text, { escape: options?.escape ?? "html" })}</code>`;
            }
            else {
                const escapedText = escapeText(text, {
                    escape: options?.escape ?? "html",
                }).replaceAll("`", "\\`");
                this.#insertComponentImport("Code");
                line = `<Code text={\`${escapedText}\`} />`;
            }
        }
        else {
            line = super.createCode(text, options ? { ...options, append: false } : undefined);
        }
        if (options?.append ?? true) {
            this.appendLine(line);
        }
        return line;
    }
    createPill(...[variant, cb, { append = false } = {}]) {
        const pill = this.#createComponent("Pill", { variant }, cb);
        if (append) {
            this.appendLine(pill);
        }
        return pill;
    }
    createOperationSection(...args) {
        this.#appendComponent("Operation", {}, () => super.createOperationSection(...args));
    }
    handleCreateOperationTitle(cb) {
        this.#appendComponent("OperationTitleSection", { slot: "title" }, cb);
    }
    handleCreateOperationSummary(cb) {
        this.#appendComponent("OperationSummarySection", { slot: "summary" }, cb);
    }
    handleCreateOperationDescription(cb) {
        this.#appendComponent("OperationDescriptionSection", { slot: "description" }, cb);
    }
    createCodeSamplesSection(...[cb]) {
        this.enterContext({ id: "code-samples", type: "section" });
        this.#appendComponent("OperationCodeSamplesSection", { slot: "code-samples" }, () => {
            this.createTabbedSection(() => {
                this.createSectionTitle(() => this.createHeading(HEADINGS.SECTION_HEADING_LEVEL, "Code Samples", {
                    id: this.getCurrentId(),
                }));
                cb({
                    createTryItNowEntry: ({ externalDependencies, defaultValue, language, }) => {
                        this.enterContext({ id: language, type: "section" });
                        this.createTabbedSectionTab(() => this.createText(getPrettyCodeSampleLanguage(language)), { id: this.getCurrentId() });
                        this.createSectionContent(() => {
                            this.#appendComponent("TryItNow", {
                                externalDependencies,
                                defaultValue,
                            });
                        }, {
                            id: this.getCurrentId(),
                        });
                        this.exitContext();
                    },
                    createCodeSampleEntry: ({ language, value }) => {
                        this.enterContext({ id: language, type: "section" });
                        this.createTabbedSectionTab(() => this.createText(getPrettyCodeSampleLanguage(language)), { id: this.getCurrentId() });
                        this.createSectionContent(() => {
                            this.#appendComponent("CodeSample", {}, () => this.createCode(value, {
                                language,
                                variant: "default",
                                style: "block",
                            }));
                        }, {
                            id: this.getCurrentId(),
                        });
                        this.exitContext();
                    },
                });
            });
        });
        this.exitContext();
    }
    createSecuritySection(...args) {
        this.#appendComponent("OperationSecuritySection", { slot: "security" }, () => super.createSecuritySection(...args));
    }
    createParametersSection(...args) {
        this.#appendComponent("OperationParametersSection", { slot: "parameters" }, () => super.createParametersSection(...args));
    }
    createRequestSection(...args) {
        this.#appendComponent("OperationRequestBodySection", { slot: "request-body" }, () => super.createRequestSection(...args));
    }
    createResponsesSection(...args) {
        this.#appendComponent("OperationResponseBodySection", { slot: "response-body" }, () => super.createResponsesSection(...args));
    }
    handleCreateRequestDisplayType(cb) {
        this.#appendComponent("OperationRequestBodyDisplayTypeSection", { slot: "request-body-display-type" }, cb);
    }
    handleCreateRequestDescription(cb) {
        this.#appendComponent("OperationRequestBodyDescriptionSection", { slot: "request-body-description" }, cb);
    }
    handleCreateRequestExamples(cb) {
        this.#appendComponent("OperationRequestBodyExamplesSection", { slot: "request-body-examples" }, cb);
    }
    handleCreateRequestDefaultValue(cb) {
        this.#appendComponent("OperationRequestBodyDefaultValueSection", { slot: "request-body-default-value" }, cb);
    }
    handleCreateResponseDisplayType(cb) {
        this.#appendComponent("OperationResponseBodyDisplayTypeSection", { slot: "response-body-display-type" }, cb);
    }
    handleCreateResponseDescription(cb) {
        this.#appendComponent("OperationResponseBodyDescriptionSection", { slot: "response-body-description" }, cb);
    }
    handleCreateResponseExamples(cb) {
        this.#appendComponent("OperationResponseBodyExamplesSection", { slot: "response-body-examples" }, cb);
    }
    handleCreateResponseDefaultValue(cb) {
        this.#appendComponent("OperationResponseBodyDefaultValueSection", { slot: "response-body-default-value" }, cb);
    }
    handleCreateSecurity(cb) {
        this.#appendComponent("ExpandableSection", {}, cb);
    }
    handleCreateParameters(cb) {
        this.#appendComponent("ExpandableSection", {}, cb);
    }
    handleCreateBreakouts(cb) {
        this.#appendComponent("ExpandableSection", {}, cb);
    }
    #getBreakoutIdInfo() {
        const stack = this.getContextStack()
            .filter((c) => c.type === "schema")
            .map((c) => c.id);
        const id = stack.join("_");
        const parentId = stack.slice(0, -1).join("_") || undefined;
        return { id, parentId };
    }
    handleCreateExpandableBreakout(...[{ hasFrontMatter, createTitle, createDescription, createExamples, createDefaultValue, isTopLevel, },]) {
        const { id, parentId } = this.#getBreakoutIdInfo();
        const expandByDefault = getSettings().display.expandTopLevelPropertiesOnPageLoad && isTopLevel;
        this.#appendComponent("ExpandableBreakout", {
            slot: "entry",
            id,
            headingId: this.getCurrentId(),
            parentId,
            hasFrontMatter,
            expandByDefault,
        }, () => {
            this.#appendComponent("ExpandableBreakoutTitle", { slot: "title" }, createTitle);
            if (createDescription) {
                this.#appendComponent("ExpandableBreakoutDescription", { slot: "description" }, createDescription);
            }
            if (createExamples) {
                this.#appendComponent("ExpandableBreakoutExamples", { slot: "examples" }, createExamples);
            }
            if (createDefaultValue) {
                this.#appendComponent("ExpandableBreakoutDefaultValue", { slot: "defaultValue" }, createDefaultValue);
            }
        });
    }
    handleCreateExpandableProperty(...[{ typeInfo, annotations, rawTitle, isTopLevel, hasFrontMatter, createDescription, createExamples, createDefaultValue, },]) {
        const { id, parentId } = this.#getBreakoutIdInfo();
        const expandByDefault = getSettings().display.expandTopLevelPropertiesOnPageLoad && isTopLevel;
        this.#appendComponent("ExpandableProperty", {
            slot: "entry",
            id,
            headingId: this.getCurrentId(),
            parentId,
            typeInfo,
            typeAnnotations: annotations,
            hasFrontMatter,
            expandByDefault,
        }, () => {
            this.#appendComponent("ExpandablePropertyTitle", { slot: "title" }, () => {
                this.createHeading(HEADINGS.PROPERTY_HEADING_LEVEL, rawTitle, {
                    id: this.getCurrentId(),
                    escape: "mdx",
                });
            });
            if (createDescription) {
                this.#appendComponent("ExpandablePropertyDescription", { slot: "description" }, createDescription);
            }
            if (createExamples) {
                this.#appendComponent("ExpandablePropertyExamples", { slot: "examples" }, createExamples);
            }
            if (createDefaultValue) {
                this.#appendComponent("ExpandablePropertyDefaultValue", { slot: "defaultValue" }, createDefaultValue);
            }
        });
    }
    createFrontMatterDisplayType(...[{ typeInfo }]) {
        this.#appendComponent("FrontMatterDisplayType", { typeInfo });
    }
    createSection(...[cb]) {
        this.#appendComponent("Section", {}, cb);
    }
    createSectionTitle(...[cb]) {
        this.#appendComponent("SectionTitle", { slot: "title" }, cb);
    }
    createSectionContent(...[cb, { id } = {}]) {
        this.#appendComponent("SectionContent", { slot: "content", id }, cb);
    }
    createTabbedSection(...[cb]) {
        // We have to do a manual Omit here, since TabbedSectionProps.children is
        // specially defined and not a standard PropsWithChildren type
        this.#appendComponent("TabbedSection", {}, cb);
    }
    createTabbedSectionTab(...[cb, { id }]) {
        this.#appendComponent("SectionTab", { slot: "tab", id }, cb);
    }
    createDebugPlaceholder(...[cb]) {
        this.#appendComponent("DebugPlaceholder", {}, cb);
    }
}
//# sourceMappingURL=mdx.js.map