import { isPrimitive } from '@redocly/theme/core/openapi';
import { getOperation, } from '../../models/index.js';
import { normalizeOptions, OpenAPIParser } from '../../services/index.js';
import { JsonPointer } from '../../utils/index.js';
export function convertOperationToReplayValue(path, method, openAPI, userClaims, operationState, appState) {
    if (!openAPI) {
        return undefined;
    }
    const parser = new OpenAPIParser(openAPI);
    const pathItem = parser.definition.paths?.[path];
    const opItem = pathItem?.[method];
    const operation = getOperation(parser, {
        ...opItem,
        pathName: path,
        httpVerb: method,
        pathParameters: pathItem.parameters || [],
        pathServers: pathItem.servers || [],
    }, undefined, normalizeOptions({}), '', { isCallback: false }, userClaims);
    if (!operation) {
        return undefined;
    }
    const activeMime = appState?.activeMimeName || 'application/json';
    const value = {
        id: operation.id,
        name: operation.name,
        method: operation.httpVerb,
        operationId: operation.operationId,
        parameters: convertParameters(operation.parameters, operationState?.requestValues),
        body: convertRequestBody(operation.requestBody, openAPI, operationState?.requestValues?.body
            ? {
                activeExampleName: operationState?.activeExampleName,
                [activeMime]: operationState?.requestValues?.body,
            }
            : operationState?.activeExampleName
                ? { activeExampleName: operationState?.activeExampleName }
                : undefined),
        path: operation.path,
        href: operation.href,
        servers: operation.servers,
        security: convertRequestSecurity(operation.security),
        responses: Object.fromEntries(operation.responses.map((response) => [
            response.code,
            {
                code: response.code,
                description: response.description,
                mediaTypes: response.content?.mediaTypes.reduce((acc, mediaType) => {
                    acc[mediaType.name] = {
                        name: mediaType.name,
                        schema: getBodySchema(mediaType.schema?.rawSchema, openAPI),
                    };
                    return acc;
                }, {}),
            },
        ])),
    };
    return value;
}
export function convertOperationToReplayValueForRedoc(userClaims) {
    return function (path, method, openAPI) {
        const replayValues = convertOperationToReplayValue(path, method, openAPI, userClaims);
        if (!replayValues) {
            return undefined;
        }
        return {
            ...replayValues,
            operationId: replayValues.operationId ||
                JsonPointer.compile(['paths', replayValues.path, replayValues.method]),
        };
    };
}
function convertParameters(params, state) {
    const seenParams = new Set();
    const allParams = params.map((param) => {
        seenParams.add(param.in + ':' + param.name);
        return {
            name: param.name,
            in: param.in,
            required: param.required,
            description: param.description,
            example: state?.[String(param.in)]?.[param.name] || param.example,
            schema: param.schema,
        };
    });
    // allow to provide extra params (not defined in the operation spec)
    for (const [inValue, param] of Object.entries(state || {})) {
        for (const [name, example] of Object.entries(param || {})) {
            if (!seenParams.has(inValue + ':' + name)) {
                allParams.push({
                    name,
                    in: inValue,
                    required: false,
                    description: '',
                    example: String(example),
                    schema: undefined,
                });
            }
        }
    }
    return allParams;
}
function getInputType({ type, format, enum: enumValue, }) {
    if (type === 'string' && (format === 'binary' || format === 'base64')) {
        return 'file';
    }
    if (type === 'object') {
        return 'multiline';
    }
    if (enumValue.length > 0) {
        return 'select';
    }
    return 'text';
}
function getFieldExamples(field, examples) {
    const example = field[0]?.example || field[0]?.examples;
    if (example) {
        return example;
    }
    if (field.schema?.example) {
        return field.schema.example;
    }
    const defaultExample = examples?.['default']?.value || examples?.['default']?.rawValue;
    if (defaultExample?.[field.name]) {
        return isPrimitive(defaultExample?.[field.name])
            ? String(defaultExample?.[field.name])
            : JSON.stringify(defaultExample?.[field.name]);
    }
    return '';
}
function convertRequestBody(requestBody, fullOpenApi, state) {
    if (!requestBody || !requestBody.content?.mediaTypes) {
        if (!state)
            return undefined;
        const { activeExampleName, ...rest } = state;
        return {
            activeExampleName,
            mediaTypes: Object.fromEntries(Object.entries(rest).map(([key, value]) => [
                key,
                { name: key, examples: { default: { value } }, schema: {}, parameters: [] },
            ])),
        };
    }
    return {
        required: requestBody.required,
        activeExampleName: state?.activeExampleName,
        mediaTypes: requestBody.content.mediaTypes.reduce((acc, mediaType) => {
            const schemaModel = mediaType.schema;
            const examples = state?.[mediaType.name]
                ? {
                    default: {
                        value: state?.[mediaType.name],
                        rawValue: state?.[mediaType.name],
                        mime: mediaType.name,
                    },
                }
                : mediaType.examples || mediaType.formExamples;
            acc[mediaType.name] = {
                name: mediaType.name,
                examples: examples,
                schema: getBodySchema(mediaType.schema?.rawSchema, fullOpenApi),
                parameters: schemaModel?.fields?.map((field) => {
                    // www-form-urlencoded and form-data
                    return {
                        inputType: getInputType(field.schema),
                        name: field.name,
                        example: getFieldExamples(field, examples),
                    };
                }),
            };
            return acc;
        }, {}),
    };
}
function getBodySchema(schema, rootDefinition) {
    if (!schema || !rootDefinition)
        return undefined;
    return {
        ...schema,
        components: rootDefinition?.components || {}, // add components to schema in case there are $refs in the original schema
    };
}
export function convertRequestSecurity(security) {
    if (!security) {
        return undefined;
    }
    return security.map(({ schemes }) => {
        return schemes.map((s) => {
            const securityScheme = {
                id: s.id,
                type: s.type,
                in: s.in,
                openIdConnectUrl: s.openIdConnectUrl,
                scopes: s.scopes,
                scheme: s.scheme,
                name: s.name,
                flows: s.flows,
                'x-defaultAccessToken': s['x-defaultAccessToken'],
                'x-defaultTokenType': s['x-defaultTokenType'],
                'x-defaultClientId': s['x-defaultClientId'],
                'x-defaultClientSecret': s['x-defaultClientSecret'],
                'x-defaultUsername': s['x-defaultUsername'],
                'x-defaultPassword': s['x-defaultPassword'],
            };
            Object.keys(securityScheme).forEach((key) => securityScheme[key] === undefined && delete securityScheme[key]);
            return securityScheme;
        });
    });
}
//# sourceMappingURL=utils.js.map