import { REDOCLY_TEAMS_RBAC } from '@redocly/config';
import { removeLeadingSlash } from '@redocly/theme/core/openapi';
import { configure } from '@redocly/theme/ext/configure';
import { extractExtensions, getOperationId, getOperationName, getStatusCodeType, getValueFromMdParsedExtension, isStatusCode, JsonPointer, mergeParams, normalizeServers, sortByDeprecated, sortByRequired, updateOperationWithRequestValues, updateParametersWithUserValues, } from '../utils/index.js';
import { getCallback } from './callback.js';
import { getField } from './field.js';
import { getRequestBody } from './request.js';
import { getSecurity } from './security.js';
import { getResponse } from './response.js';
import { getHref } from '../services/menu/operation.js';
export function isPayloadSample(sample) {
    return sample.lang === 'Payload' && 'requestBodyContent' in sample;
}
export function getOperation(parser, operationDefinition, parent, options, href, callback, userClaims) {
    const isWebhook = operationDefinition.isWebhook;
    const operation = {
        operationDefinition,
        parent,
        pointer: operationDefinition.pointer,
        description: getValueFromMdParsedExtension(operationDefinition, 'description'),
        externalDocs: operationDefinition.externalDocs,
        deprecated: !!operationDefinition.deprecated,
        httpVerb: operationDefinition.httpVerb,
        operationId: operationDefinition.operationId,
        path: operationDefinition.pathName,
        isWebhook,
        isCallback: Boolean(callback?.isCallback),
        isEvent: callback?.isCallback || isWebhook,
        name: getOperationName(operationDefinition),
        defaultExampleName: operationDefinition.defaultSampleName,
        [REDOCLY_TEAMS_RBAC]: operationDefinition[REDOCLY_TEAMS_RBAC] || parent?.[REDOCLY_TEAMS_RBAC],
        type: 'operation',
        callbackId: callback?.id,
        href,
        get callbacks() {
            return Object.keys(operationDefinition.callbacks || []).map((callbackEventName) => {
                return getCallback(parser, callbackEventName, operationDefinition.callbacks?.[callbackEventName], operation.pointer, options, href, parent, userClaims);
            });
        },
        get responses() {
            let hasSuccessResponses = false;
            return Object.keys(operationDefinition.responses || [])
                .filter((code) => {
                if (code === 'default') {
                    return true;
                }
                if (getStatusCodeType(code) === 'success') {
                    hasSuccessResponses = true;
                }
                return isStatusCode(code);
            }) // filter out other props (e.g. x-props)
                .map((code) => {
                return getResponse({
                    parser,
                    code,
                    defaultAsError: hasSuccessResponses,
                    infoOrRef: operationDefinition.responses[code],
                    options,
                    isEvent: operation.isEvent,
                    operation,
                });
            });
        },
        get parameters() {
            return processParameters(parser, operationDefinition, operation, options, userDefinedRequestValues);
        },
    };
    if (callback?.isCallback) {
        // NOTE: Callbacks by default should not inherit the specification's global `security` definition.
        // Can be defined individually per-callback in the specification. Defaults to none.
        operation.security = getSecurity(operationDefinition.security, parser);
        // TODO: update getting pathInfo for overriding servers on path level
        operation.servers = normalizeServers('', operationDefinition.servers || operationDefinition.pathServers || []);
        // TODO: remove it when all deep links are updated with one proper handler
        operation.id = removeLeadingSlash(href); // pass operation href as id for callbacks
    }
    else {
        operation.id = getOperationId(operationDefinition, parent);
        operation.href = operation.href || getHref(operation);
        operation.security = getSecurity(operationDefinition.security || parser.definition.security, parser);
        const servers = operationDefinition.servers ||
            (operationDefinition.pathServers?.length ? operationDefinition.pathServers : null) ||
            parser.definition.servers ||
            [];
        operation.servers = normalizeServers(parser.definitionUrl, mergeInMockServer(servers, options.mockServer));
    }
    if (options.showExtensions) {
        operation.extensions = extractExtensions(operationDefinition, options.showExtensions);
    }
    operation.requestBody = operationDefinition.requestBody
        ? getRequestBody({
            parser: parser,
            infoOrRef: operationDefinition.requestBody,
            options,
            operation,
            isEvent: operation.isEvent,
        })
        : undefined;
    const requestBodyContent = operation.requestBody?.content;
    operation.payload = {
        lang: 'Payload',
        source: '',
        requestBodyContent: requestBodyContent?.hasSample ? requestBodyContent : undefined,
    };
    operation.definitionSamples = operationDefinition['x-codeSamples'] || [];
    operation.badges =
        operationDefinition['x-badges']?.map(({ name, color, position }) => ({
            name,
            color: color || 'var(--color-info-base)',
            position: position || 'after',
        })) || [];
    operation.hasSamples = requestBodyContent?.hasSample || operation.definitionSamples.length > 0;
    operation.hideReplay = operationDefinition['x-hideReplay'] === true;
    const operationParams = {
        userClaims,
        operation: {
            operationId: operation.operationId,
            name: operation.name,
            path: operation.path,
            href: operation.href,
            method: operation.httpVerb,
        },
        servers: operation.servers,
    };
    const configResult = configure(operationParams) || {};
    const userDefinedRequestValues = configResult.requestValues || {};
    updateOperationWithRequestValues(operation, userDefinedRequestValues);
    return operation;
}
function processParameters(parser, operationDefinition, operation, options, userDefinedRequestValues) {
    let parameters = mergeParams(parser, operationDefinition.pathParameters, operationDefinition.parameters, {
        pathPointer: JsonPointer.dirName(operation.pointer),
        operationPointer: operation.pointer,
    }).map(({ paramOrRef, pointer }) => {
        const param = getField(parser, paramOrRef, pointer, options, {
            operation,
            type: 'request',
        });
        updateParametersWithUserValues(param, userDefinedRequestValues);
        return param;
    });
    if (options.sortRequiredPropsFirst) {
        parameters = sortByRequired(parameters);
    }
    return sortByDeprecated(parameters);
}
export function mergeInMockServer(servers, mockServerOptions) {
    if (!mockServerOptions) {
        return servers;
    }
    const mockServer = {
        url: mockServerOptions.url,
        description: mockServerOptions.description,
    };
    switch (mockServerOptions.position) {
        case 'first':
            return [mockServer, ...servers];
        case 'last':
            return [...servers, mockServer];
        case 'replace':
            return [mockServer];
        default:
            return servers;
    }
}
//# sourceMappingURL=operation.js.map