"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.OperationValidator = void 0;
const utils_1 = require("@autobe/utils");
const tstl_1 = require("tstl");
const Escaper_1 = require("typia/lib/utils/Escaper");
const emplaceMap_1 = require("../../../utils/emplaceMap");
const JsonSchemaValidator_1 = require("./JsonSchemaValidator");
var OperationValidator;
(function (OperationValidator) {
    OperationValidator.validate = (props) => {
        props.operations.forEach((op, i) => {
            // get method has request body
            if (op.method === "get" && op.requestBody !== null)
                props.errors.push({
                    path: `${props.path}[${i}].requestBody`,
                    expected: "GET method should not have request body. Change method, or re-design the operation.",
                    value: op.requestBody,
                });
            // operation name
            if (Escaper_1.Escaper.variable(op.name) === false)
                props.errors.push({
                    path: `${props.path}[${i}].name`,
                    expected: "<valid_variable_name>",
                    value: op.name,
                    description: utils_1.StringUtil.trim `
            The operation name will be converted to the API controller method
            (function) name, so the operation.name must be a valid JavaScript 
            variable/function name.

            However, what you've configured value ${JSON.stringify(op.name)}
            is not a valid JavaScript variable/function name. Please change
            it to a valid variable/function name.
          `,
                });
            // validate types
            if (op.requestBody !== null)
                JsonSchemaValidator_1.JsonSchemaValidator.validateKey({
                    errors: props.errors,
                    path: `${props.path}[${i}].requestBody.typeName`,
                    key: op.requestBody.typeName,
                });
            if (op.responseBody !== null) {
                JsonSchemaValidator_1.JsonSchemaValidator.validateKey({
                    errors: props.errors,
                    path: `${props.path}[${i}].responseBody.typeName`,
                    key: op.responseBody.typeName,
                });
            }
        });
        // validate duplicated endpoints
        const endpoints = new tstl_1.HashMap(utils_1.AutoBeEndpointComparator.hashCode, utils_1.AutoBeEndpointComparator.equals);
        props.operations.forEach((op, i) => {
            const key = {
                path: op.path,
                method: op.method,
            };
            const it = endpoints.find(key);
            if (it.equals(endpoints.end()) === false) {
                const indexes = it.second;
                props.errors.push({
                    path: `${props.path}[${i}].{"path"|"method"}`,
                    expected: "Unique endpoint (path and method)",
                    value: key,
                    description: utils_1.StringUtil.trim `
            Duplicated endpoint detected (method: ${op.method}, path: ${op.path}).

            The duplicated endpoints of others are located in below accessors.
            Check them, and consider which operation endpoint would be proper to modify.
            
            ${indexes
                        .map((idx) => `- ${props.path}.[${idx}].{"path"|"method"}`)
                        .join("\n")}
          `,
                });
                indexes.push(i);
            }
            else
                endpoints.emplace(key, [i]);
        });
        // validate duplicated method names
        const accessors = new Map();
        props.operations.forEach((op, i) => {
            const key = op.path
                .split("/")
                .filter((e) => e[0] !== "{" && e.at(-1) !== "}")
                .filter((e) => e.length !== 0)
                .join(".") + `.${op.name}`;
            const indexes = (0, emplaceMap_1.emplaceMap)(accessors, key, () => []);
            if (indexes.length !== 0) {
                props.errors.push({
                    path: `${props.path}[${i}].name`,
                    expected: "Unique name in the same accessor scope.",
                    value: op.name,
                    description: utils_1.StringUtil.trim `
            Duplicated operation accessor detected (name: ${op.name}, accessor: ${key}).

            The operation name must be unique within the parent accessor.
            In other worlds, the operation accessor determined by the name
            must be unique in the OpenAPI document.

            Here is the list of elements of duplicated operation names.
            Check them, and consider which operation name would be proper to modify.

            ${indexes
                        .map((idx) => `- ${props.operations[idx].name} (accessor: ${key})`)
                        .join("\n")}
          `,
                });
            }
            indexes.push(i);
        });
    };
})(OperationValidator || (exports.OperationValidator = OperationValidator = {}));
//# sourceMappingURL=OperationValidator.js.map