"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.OpenAPI2 = void 0;
const openapi_types_1 = require("openapi-types");
const openapi_1 = require("./base/openapi");
const url_1 = require("url");
const parameterNotRef = (param) => {
    // all refs are deferenced by parser library
    return true;
};
const isOpenAPI2 = (document) => {
    if (document.swagger === "2.0") {
        return true;
    }
    else {
        return false;
    }
};
const methods = Object.values(openapi_types_1.OpenAPIV2.HttpMethods);
const isOperation = (key, pathItem) => {
    return methods.includes(key);
};
const isParameter = (key, pathItem) => {
    return !isOperation(key, pathItem);
};
/**
 * OpenAPI Version 2.0 - aka "Swagger"
 * https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md
 */
class OpenAPI2 extends openapi_1.OpenAPISource {
    constructor() {
        super(...arguments);
        this.isSupported = (data) => __awaiter(this, void 0, void 0, function* () {
            try {
                const document = yield this.parseData(data);
                if (isOpenAPI2(document)) {
                    this.document = document;
                    return true;
                }
                else {
                    return false;
                }
            }
            catch (err) {
                return false;
            }
        });
        this.getUrl = () => {
            var _a;
            const scheme = ((_a = this.document.schemes) === null || _a === void 0 ? void 0 : _a.includes("https")) ? "https" : "http";
            const basePath = this.document.basePath || "";
            const host = this.document.host || "<host>";
            return new url_1.URL(`${scheme}://${host}${basePath}`);
        };
        this.getInfo = () => __awaiter(this, void 0, void 0, function* () {
            const name = this.document.info.title || "Swagger Import";
            return {
                name,
            };
        });
        this.getQueries = (datasourceId) => __awaiter(this, void 0, void 0, function* () {
            const url = this.getUrl();
            const queries = [];
            for (let [path, pathItem] of Object.entries(this.document.paths)) {
                // parameters that apply to every operation in the path
                let pathParams = [];
                for (let [key, opOrParams] of Object.entries(pathItem)) {
                    if (isParameter(key, opOrParams)) {
                        const pathParameters = opOrParams;
                        pathParams.push(...pathParameters);
                        continue;
                    }
                    // can not be a parameter, must be an operation
                    const operation = opOrParams;
                    const methodName = key;
                    const name = operation.operationId || path;
                    let queryString = "";
                    const headers = {};
                    let requestBody = undefined;
                    const parameters = [];
                    if (operation.consumes) {
                        headers["Content-Type"] = operation.consumes[0];
                    }
                    // combine the path parameters with the operation parameters
                    const operationParams = operation.parameters || [];
                    const allParams = [...pathParams, ...operationParams];
                    for (let param of allParams) {
                        if (parameterNotRef(param)) {
                            switch (param.in) {
                                case "query":
                                    let prefix = "";
                                    if (queryString) {
                                        prefix = "&";
                                    }
                                    queryString = `${queryString}${prefix}${param.name}={{${param.name}}}`;
                                    break;
                                case "header":
                                    headers[param.name] = `{{${param.name}}}`;
                                    break;
                                case "path":
                                    // do nothing: param is already in the path
                                    break;
                                case "formData":
                                    // future enhancement
                                    break;
                                case "body":
                                    // set the request body to the example provided
                                    // future enhancement: generate an example from the schema
                                    let bodyParam = param;
                                    if (param.schema.example) {
                                        const schema = bodyParam.schema;
                                        requestBody = schema.example;
                                    }
                                    break;
                            }
                            // add the parameter if it can be bound in our config
                            if (["query", "header", "path"].includes(param.in)) {
                                parameters.push({
                                    name: param.name,
                                    default: param.default || "",
                                });
                            }
                        }
                    }
                    const query = this.constructQuery(datasourceId, name, methodName, path, url, queryString, headers, parameters, requestBody);
                    queries.push(query);
                }
            }
            return queries;
        });
    }
    getImportSource() {
        return "openapi2.0";
    }
}
exports.OpenAPI2 = OpenAPI2;
