import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import openapisMap from 'doom-@api-openapisMap';
import { useId, useMemo } from 'react';
import { usePageData } from 'rspress/runtime';
import { modelName, omitRoutePathRefs, resolveRef } from '../utils.js';
import { Markdown } from './Markdown.js';
import { HeadingTitle } from './_HeadingTitle.js';
import { RefLink } from './_RefLink.js';
import { X } from './_X.js';
import { UidProvider, useUid } from './_context.js';
export const OpenAPIProperty = ({ name, property, openapi, }) => {
    const propObj = '$ref' in property ? resolveRef(openapi, property.$ref) : property;
    const type = propObj.type;
    let typeNode;
    let extraNode;
    if (type === 'array') {
        const { items } = propObj;
        const itemsObj = '$ref' in items ? resolveRef(openapi, items.$ref) : items;
        const itemsType = itemsObj.type;
        typeNode = (_jsxs("code", { children: ["[]", '$ref' in items ? _jsx(RefLink, { "$ref": items.$ref }) : itemsType] }));
    }
    else if (type === 'object') {
        if ('properties' in property && property.properties) {
            extraNode = (_jsxs("div", { className: "my-4", children: [_jsx("em", { children: "Properties:" }), _jsx(OpenAPIProperties, { properties: property.properties, openapi: openapi })] }));
        }
        if (typeof propObj.additionalProperties === 'object') {
            const props = propObj.additionalProperties;
            const propsObj = '$ref' in props ? resolveRef(openapi, props.$ref) : props;
            const propsType = propsObj.type;
            typeNode = (_jsxs("code", { children: ["map[string]", typeof propsType === 'string'
                        ? propsType
                        : '$ref' in props && _jsx(RefLink, { "$ref": props.$ref })] }));
        }
        else {
            typeNode = _jsx("code", { children: type });
        }
    }
    else if (typeof type === 'string') {
        typeNode = _jsx("code", { children: type });
    }
    else if ('$ref' in property) {
        typeNode = _jsx(RefLink, { "$ref": property.$ref });
    }
    return (_jsxs(_Fragment, { children: [name && (_jsxs(_Fragment, { children: [_jsx("code", { children: name }), ":", ' '] })), typeNode, _jsx(Markdown, { children: propObj.description }), extraNode] }));
};
export const OpenAPIProperties = ({ properties, openapi, }) => {
    return (_jsx(X.ul, { children: Object.entries(properties).map(([name, property]) => (_jsx(X.li, { children: _jsx(OpenAPIProperty, { name: name, property: property, openapi: openapi }) }, name))) }));
};
const getRefsForSchema = (openapi, schema, knownRefs) => {
    const refSchema = openapi.components?.schemas[schema];
    if (!refSchema) {
        return [];
    }
    const refs = new Set();
    const collectRefs = (schema) => {
        if ('$ref' in schema && typeof schema.$ref === 'string') {
            const ref = schema.$ref.replace('#/components/schemas/', '');
            if (!knownRefs[ref]) {
                refs.add(ref);
                schema = resolveRef(openapi, schema.$ref);
            }
        }
        for (const value of Object.values(schema)) {
            if (value && typeof value === 'object') {
                collectRefs(value);
            }
        }
    };
    collectRefs(refSchema);
    return Array.from(refs);
};
export const OpenAPIRef = ({ schema, openapiPath: openapiPath_, isCommonRef = true, collectRefs = true, }) => {
    const { page } = usePageData();
    let uid = useUid();
    const innerUid = useId();
    if (isCommonRef) {
        uid = ''; // common references do not need a unique ID
    }
    else if (!uid) {
        uid = innerUid;
    }
    const [schemaItem, openapi, openapiPath] = useMemo(() => {
        for (const [pathname, openapi] of Object.entries(openapisMap)) {
            if (openapiPath_ && pathname !== openapiPath_) {
                continue;
            }
            const schemaItem = openapi.components?.schemas?.[schema];
            if (schemaItem) {
                return [schemaItem, openapi, pathname];
            }
        }
        return [];
    }, [openapiPath_, schema]);
    const refs = useMemo(() => {
        if (collectRefs && openapi) {
            return getRefsForSchema(openapi, schema, omitRoutePathRefs(page.routePath));
        }
    }, [collectRefs, openapi, page.routePath, schema]);
    if (!schemaItem || !openapi) {
        console.error(`No OpenAPI schema definition found for ${schema}\n`);
        return null;
    }
    return (_jsxs(UidProvider, { value: uid, children: [_jsx(HeadingTitle, { slug: schema, level: 2, children: modelName(schema) }), _jsx(Markdown, { children: schemaItem.description }), schemaItem.properties && (_jsx(OpenAPIProperties, { properties: schemaItem.properties, openapi: openapi })), refs?.map((schema) => (_jsx(OpenAPIRef, { schema: schema, openapiPath: openapiPath, isCommonRef: isCommonRef, collectRefs: false }, schema)))] }));
};
export default OpenAPIRef;
