"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.API_STEPS_FEATURE = void 0;
exports.humanizeSendHttpRequestStep = humanizeSendHttpRequestStep;
exports.sendHttpRequestStepToAIString = sendHttpRequestStepToAIString;
const BaseStep_1 = __importDefault(require("./BaseStep"));
const dom_util_1 = require("@mablhq-internal/mablscript-find/dom-util");
const mablscriptFind_1 = require("@mablhq/test-model/mablscriptFind");
const common_1 = require("../../common");
const type_utils_1 = require("../../type-utils");
const variable_names_util_1 = require("../../variable-names-util");
const mablscript_step_types_1 = require("../../mablscript-step-types");
const variable_constants_1 = require("../../variable-constants");
const yaml_utils_1 = require("../yaml-utils");
const BASIC_AUTH = { value: 'basic', label: 'Basic' };
const BEARER_AUTH = { value: 'bearer', label: 'Bearer' };
exports.API_STEPS_FEATURE = Object.freeze({
    id: 'api_steps',
    label: 'API Steps',
});
class SendHttpRequestStep extends BaseStep_1.default {
    static getStepType() {
        return mablscript_step_types_1.StepType.SEND_HTTP_REQUEST;
    }
    constructor(request, responseAssertions, responseVariables, advancedOptions, response, variables) {
        super(SendHttpRequestStep.getStepType());
        this.request = request;
        this.responseAssertions = responseAssertions;
        this.responseVariables = responseVariables;
        this.advancedOptions = advancedOptions;
        this.mergeOptions({
            editable: true,
            executionContext: 'background',
            feature: exports.API_STEPS_FEATURE,
        });
        this.response = response;
        this.variables = variables;
    }
    generateMablscript() {
        const httpRequest = {
            request: {
                url: this.request.url,
                method: this.request.method,
            },
        };
        if (isNotEmpty(this.request.headers)) {
            httpRequest.request.headers = this.request.headers?.map(({ name, value }) => ({ name, value }));
        }
        switch (this.request?.authorization?.type) {
            case BASIC_AUTH.value: {
                const props = this.request?.authorization?.properties;
                httpRequest.request.authorization = {
                    type: 'basic',
                    properties: {
                        username: props?.username,
                        password: props?.password,
                    },
                };
                break;
            }
            case BEARER_AUTH.value: {
                const props = this.request?.authorization?.properties;
                httpRequest.request.authorization = {
                    type: 'bearer',
                    properties: {
                        token: props?.token ?? '',
                    },
                };
                break;
            }
        }
        if (isNotEmpty(this.request.body)) {
            httpRequest.request.body = this.request.body;
        }
        if (isNotEmpty(this.responseAssertions)) {
            httpRequest.assertions = this.responseAssertions?.map(({ source, target, assertion, value }) => {
                const scrubbedTarget = target?.trim()
                    ? stringify(target.trim())
                    : undefined;
                return {
                    source,
                    target: scrubbedTarget,
                    assertion,
                    value: stringify(value),
                };
            });
        }
        if (isNotEmpty(this.responseVariables)) {
            httpRequest.variables = this.responseVariables?.map(({ source, target, name }) => {
                const scrubbedTarget = target?.trim()
                    ? stringify(target.trim())
                    : undefined;
                return { source, target: scrubbedTarget, name };
            });
        }
        if (this.advancedOptions) {
            httpRequest.options = this.advancedOptions;
        }
        return `send_http_request(${(0, mablscriptFind_1.buildStepArgumentString)({
            params: { ...httpRequest },
            legacy: true,
        })})`;
    }
    inputVariables() {
        const item = {
            request: this.request,
            responseAssertions: this.responseAssertions,
            responseVariables: this.responseVariables,
        };
        return (0, type_utils_1.distinct)((0, variable_names_util_1.extractVariableNamesFromPattern)(JSON.stringify(item)));
    }
    static generateStepFromMablStep(mablSendHttpRequestStep, importer) {
        const { request, assertions: responseAssertions, variables: responseVariables, options: advancedOptions, } = mablSendHttpRequestStep.descriptor;
        let variables = [];
        if (responseVariables) {
            variables = responseVariables.map(({ name: variableName }) => {
                const userScopedVariableName = `user.${variableName}`;
                const variable = {
                    name: userScopedVariableName,
                    humanizedName: variableName,
                    variableType: 'api',
                    value: variable_constants_1.EMPTY_VARIABLE_VALUE_PLACEHOLDER,
                };
                importer.variables[userScopedVariableName] = { ...variable };
                return variable;
            });
        }
        return new SendHttpRequestStep(request, responseAssertions, responseVariables, advancedOptions, undefined, variables);
    }
    static create(descriptor) {
        const step = new SendHttpRequestStep(descriptor.request, descriptor.responseAssertions, descriptor.responseVariables, descriptor.advancedOptions, descriptor.response, descriptor.variables);
        step.generateStepId();
        return step;
    }
}
exports.default = SendHttpRequestStep;
function humanizeResponseTarget(source, target) {
    switch (source) {
        case 'status':
            return `response status`;
        case 'header':
            return `response header "${stringify(target)}"`;
        case 'json':
            return target
                ? `"${target}" of response body as json`
                : 'response body as json';
        case 'text':
            return `response body as text`;
        case 'response':
        default:
            return source;
    }
}
function humanizeSendHttpRequestStep(step) {
    const descriptions = [];
    descriptions.push(`Send ${step.request.method.toUpperCase()} request to "${(0, mablscriptFind_1.humanizeUrl)(step.request.url)}"`);
    descriptions.push(humanizeResponseAssertions(step, 2));
    descriptions.push(humanizeResponseVariables(step, 2));
    return (0, dom_util_1.compactWhitespace)((0, mablscriptFind_1.humanizeValueArray)(descriptions.filter((description) => description), ';'));
}
function humanizeResponseAssertions(step, maxlen) {
    const count = step.responseAssertions?.length;
    if (!count) {
        return '';
    }
    if (maxlen && count > maxlen) {
        return `make ${count} assertions against the response`;
    }
    const assertionDescriptions = step.responseAssertions?.map(({ source, target, assertion, value }) => `${humanizeResponseTarget(source, target ?? '')} ${(0, common_1.getAssertionHumanizedText)(assertion)} "${(0, mablscriptFind_1.humanizeValue)(stringify(value), 20)}"`);
    return `assert ${(0, mablscriptFind_1.humanizeValueArray)(assertionDescriptions)}`;
}
function humanizeResponseVariables(step, maxlen) {
    const count = step.responseVariables?.length;
    if (!count) {
        return '';
    }
    if (maxlen && count > maxlen) {
        const variableNames = step.responseVariables?.map(({ name }) => `"${name}"`);
        return `create variables ${(0, mablscriptFind_1.humanizeValueArray)(variableNames)} from the response`;
    }
    const variableDescriptions = step.responseVariables?.map(({ source, target, name }) => `${humanizeResponseTarget(source, target ?? '')} in variable "${name}"`);
    return `store ${(0, mablscriptFind_1.humanizeValueArray)(variableDescriptions)}`;
}
function isNotEmpty(array) {
    return !!array && array.length > 0;
}
const stringify = (value) => nil(value)
    ? ''
    : typeof value === 'object'
        ? JSON.stringify(value)
        : `${value}`;
const nil = (value) => value === undefined || value === null;
function sendHttpRequestStepToAIString(step) {
    const result = {
        stepType: step.stepType,
        method: step.request.method,
        url: step.request.url,
    };
    if (step.request.headers && step.request.headers.length > 0) {
        result.headers = step.request.headers.map((h) => ({
            name: h.name,
            value: h.value,
        }));
    }
    if (step.request.authorization?.type) {
        result.authorization = {
            type: step.request.authorization.type,
        };
    }
    if (step.request.body) {
        result.body = step.request.body;
    }
    if (step.responseAssertions && step.responseAssertions.length > 0) {
        result.assertions = step.responseAssertions.map((a) => ({
            source: a.source,
            target: a.target,
            assertion: a.assertion,
            value: a.value,
        }));
    }
    if (step.responseVariables && step.responseVariables.length > 0) {
        result.variables = step.responseVariables.map((v) => ({
            source: v.source,
            target: v.target,
            name: v.name,
        }));
    }
    return (0, yaml_utils_1.toYaml)(result);
}
