import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { usePageData } from '@rspress/core/runtime';
import { Badge } from '@rspress/core/theme';
import openapisMap from 'doom-@api-openapisMap';
import virtual from 'doom-@api-virtual';
import BananaSlug from 'github-slugger';
import { OpenAPIV3 } from 'openapi-types';
import { Fragment, useId, useMemo } from 'react';
import { omitRoutePathRefs, resolveRef } from '../utils.js';
import { OpenAPIProperties, OpenAPIProperty, OpenAPIRef } from './OpenAPIRef.js';
import { HeadingTitle } from './_HeadingTitle.js';
import { Markdown } from './_Markdown.js';
import { RefLink } from './_RefLink.js';
import { X } from './_X.js';
export const OpenAPIParameters = ({ parameters, openapi, }) => {
    return (_jsx(X.ul, { children: parameters.map((param, index) => {
            const paramObj = '$ref' in param
                ? resolveRef(openapi, param.$ref)
                : param;
            const type = paramObj.schema &&
                ('$ref' in paramObj.schema ? paramObj.schema : paramObj.schema.type);
            let typeNode;
            if (typeof type === 'string') {
                typeNode = _jsx("code", { children: type });
            }
            else if (type) {
                typeNode = _jsx(RefLink, { "$ref": type.$ref });
            }
            return (
            // eslint-disable-next-line @eslint-react/no-array-index-key
            _jsxs(X.li, { children: [_jsx("code", { children: paramObj.name }), " (", _jsxs("em", { children: ["in ", paramObj.in] }), "): ", typeNode, paramObj.required && (_jsxs(_Fragment, { children: [' ', _jsx(Badge, { children: "required" })] })), _jsxs(_Fragment, { children: [' ', _jsx(Markdown, { children: paramObj.description })] })] }, index));
        }) }));
};
export const OpenAPIResponses = ({ responses, openapi, }) => {
    return (_jsx(X.ul, { children: Object.entries(responses).map(([code, response]) => {
            const responseObj = '$ref' in response
                ? resolveRef(openapi, response.$ref)
                : response;
            const responseContent = responseObj.content;
            const schema = (responseContent?.['application/json'] ?? responseContent?.['*/*'])?.schema;
            const type = schema && ('$ref' in schema ? schema : schema.type);
            let typeNode;
            let extraNode;
            if (typeof type === 'string') {
                typeNode = _jsx("code", { children: type });
                if (type === 'object' &&
                    'properties' in schema &&
                    schema.properties) {
                    extraNode = (_jsxs("div", { className: "my-4", children: [_jsx("em", { children: "Properties:" }), _jsx(OpenAPIProperties, { properties: schema.properties, openapi: openapi })] }));
                }
                else if (type === 'array' && 'items' in schema && schema.items) {
                    extraNode = (_jsxs("div", { className: "my-4", children: [_jsx("em", { children: "Items:" }), _jsx(OpenAPIProperty, { property: schema.items, openapi: openapi })] }));
                }
            }
            else if (type && '$ref' in type) {
                typeNode = _jsx(RefLink, { "$ref": type.$ref });
            }
            return (_jsxs(X.li, { children: [_jsx("code", { children: code }), typeNode, ": ", responseObj.description, extraNode] }, code));
        }) }));
};
const getRefsForPath = (openapi, path, knownRefs) => {
    const pathSchema = openapi.paths?.[path];
    if (!pathSchema) {
        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);
            }
        }
    };
    for (const method of Object.values(OpenAPIV3.HttpMethods)) {
        if (pathSchema[method]?.requestBody) {
            collectRefs(pathSchema[method].requestBody);
        }
        if (pathSchema[method]?.responses) {
            for (const response in pathSchema[method].responses) {
                collectRefs(pathSchema[method].responses[response]);
            }
        }
    }
    return Array.from(refs);
};
export const OpenAPIPath = ({ path, openapiPath: openapiPath_, pathPrefix: pathPrefix_, }) => {
    const { page } = usePageData();
    const pathPrefix = pathPrefix_ ?? (virtual.pathPrefix || '');
    const uid = useId();
    const slugger = useMemo(() => new BananaSlug(), []);
    const [pathItem, openapi, openapiPath, refs] = useMemo(() => {
        for (const [pathname, openapi] of Object.entries(openapisMap)) {
            if (openapiPath_ && pathname !== openapiPath_) {
                continue;
            }
            const pathItem = openapi.paths?.[path];
            if (pathItem) {
                return [
                    pathItem,
                    openapi,
                    pathname,
                    getRefsForPath(openapi, path, omitRoutePathRefs(page.routePath)),
                ];
            }
        }
        return [];
    }, [openapiPath_, page.routePath, path]);
    if (!pathItem || !openapi) {
        console.error(`No OpenAPI path definition found for ${path}`);
        return null;
    }
    return (_jsxs(_Fragment, { children: [_jsxs(HeadingTitle, { slugger: slugger, uid: uid, level: 2, children: [pathPrefix, path] }), pathItem.parameters && (_jsxs(_Fragment, { children: [_jsx(HeadingTitle, { slugger: slugger, uid: uid, level: 3, children: "Common Parameters" }), _jsx(OpenAPIParameters, { parameters: pathItem.parameters, openapi: openapi })] })), Object.values(OpenAPIV3.HttpMethods).map((method) => {
                if (!pathItem[method]) {
                    return null;
                }
                const { description, parameters, requestBody, responses, summary } = pathItem[method];
                const requestBodyRef = requestBody &&
                    ('$ref' in requestBody
                        ? requestBody.$ref
                        : requestBody.content['application/json'].schema?.$ref);
                const requestBodySchema = requestBodyRef
                    ? resolveRef(openapi, requestBodyRef)
                    : undefined;
                return (_jsxs(Fragment, { children: [_jsxs(HeadingTitle, { slugger: slugger, uid: uid, level: 3, children: [_jsx("code", { children: method }), summary] }), _jsx(Markdown, { children: description }), parameters && (_jsxs(_Fragment, { children: [_jsx(HeadingTitle, { slugger: slugger, uid: uid, level: 4, children: "Parameters" }), _jsx(OpenAPIParameters, { parameters: parameters, openapi: openapi })] })), requestBodySchema && (_jsxs(_Fragment, { children: [_jsx(HeadingTitle, { slugger: slugger, uid: uid, level: 4, children: "Request Body" }), _jsxs(X.p, { children: [_jsx(RefLink, { "$ref": requestBodyRef }), requestBodySchema.required && _jsx(Badge, { children: "required" })] })] })), responses && (_jsxs(_Fragment, { children: [_jsx(HeadingTitle, { slugger: slugger, uid: uid, level: 4, children: "Response" }), _jsx(OpenAPIResponses, { responses: responses, openapi: openapi })] }))] }, method));
            }), refs?.map((ref) => {
                return (_jsx(OpenAPIRef, { schema: ref, openapiPath: openapiPath, uid: uid, collectRefs: false }, ref));
            })] }));
};
export default OpenAPIPath;
