import stringifyObject from 'stringify-object';
import { CodeBuilder } from '../../helpers/code-builder.js';
import { HTTPSnippet } from '../../index.js';
import { Lang } from '../../helpers/constants.js';
import { buildUrlExpression, printUrlVariablesDeclarations } from '../../helpers/code-helpers.js';
import { normalizeMimeType } from '../../../../utils.js';
import { MediaTypes } from '../../../../../constants.js';
const indent = 1;
function hasMimeType(postData = {}, mimeType) {
    return normalizeMimeType(postData.mimeType) === mimeType;
}
const handler = function (source, originalOptions, { target, client }) {
    const reqMethod = source.method.toUpperCase();
    const securityOAuth2ExtraCalls = source.securityOAuth2ExtraCalls?.[0];
    const options = {
        capitalize: true,
        showBoilerplate: true,
        indent: '  ',
        ...originalOptions,
    };
    const code = new CodeBuilder({
        indentation: options.indent,
        variablesPrefix: options.variablesPrefix,
        capitalize: options.capitalize,
        lang: Lang.RUBY,
    });
    // Print boilerplate with packages initialization:
    if (options.showBoilerplate) {
        code.push(`require 'uri'`).push(`require 'net/http'`);
        if (source.uriObj.protocol === 'https:') {
            code.push(`require 'openssl'`);
        }
        if (hasMimeType(source.postData, MediaTypes.JSON) || securityOAuth2ExtraCalls) {
            code.unshift(`require 'json'`);
        }
        code.blank();
    }
    // Put headers values into quotation marks
    if (Object.keys(source.allHeaders).length) {
        Object.keys(source.allHeaders).forEach((key) => {
            source.allHeaders[key] = `'${source.allHeaders[key]}'`;
        });
    }
    // To support custom methods we check for the supported methods
    // and if doesn't exist then we build a custom class for it
    const methods = [
        'GET',
        'POST',
        'HEAD',
        'DELETE',
        'PATCH',
        'PUT',
        'OPTIONS',
        'COPY',
        'LOCK',
        'UNLOCK',
        'MOVE',
        'TRACE',
    ];
    const capMethod = reqMethod.charAt(0) + reqMethod.substring(1).toLowerCase();
    if (methods.indexOf(reqMethod) < 0) {
        code
            .push('class Net::HTTP::%s < Net::HTTPRequest', capMethod)
            .push("  METHOD = '%s'", reqMethod.toUpperCase())
            .push("  REQUEST_HAS_BODY = '%s'", source.postData?.text ? 'true' : 'false')
            .push('  RESPONSE_HAS_BODY = true')
            .push('end')
            .blank();
    }
    // If we have extra OAuth calls - print code for that
    if (securityOAuth2ExtraCalls) {
        const prefix = 'oAuth2';
        const oAuth2PrefixCode = new HTTPSnippet(securityOAuth2ExtraCalls).convert(target, client, {
            ...options,
            variablesPrefix: prefix,
            showBoilerplate: false,
        });
        const responseVariable = `${prefix}${options.capitalize ? 'Response' : 'response'}`;
        code
            .push(oAuth2PrefixCode)
            .push(`access_token = JSON.parse(${responseVariable}.body)['access_token']`)
            .blank();
        source.allHeaders.Authorization = `"Bearer " + access_token`;
    }
    // Print the URL with path variables if present
    printUrlVariablesDeclarations(source, code);
    code.push(`${code.var('url')} = URI(${buildUrlExpression(source, code)})`);
    // Print query variables if present
    const hasQueryVariables = Object.getOwnPropertyNames(source.queryObj).length;
    if (hasQueryVariables) {
        code.push(`${code.var('params')} = ${stringifyObject(source.queryObj, {
            indent: options.indent,
            inlineCharacterLimit: 25,
        })}`);
        code.push(`${code.var('url')}.query = URI.encode_www_form(${code.var('params')})`);
    }
    // Print code with client initialization
    code
        .blank()
        .push(`${code.var('http')} = Net::HTTP.new(${code.var('url')}.host, ${code.var('url')}.port)`);
    if (source.uriObj.protocol === 'https:') {
        code.push(`${code.var('http')}.use_ssl = true`);
    }
    code.blank().push(`${code.var('request')} = Net::HTTP::%s.new(${code.var('url')})`, capMethod);
    // Print headers
    if (Object.keys(source.allHeaders).length) {
        Object.keys(source.allHeaders).forEach((key) => {
            if (source.allHeaders[key] !== `'${MediaTypes.MULTIPART}'`) {
                // we'll set multipart/form-data later
                code.push(`${code.var('request')}['%s'] = %s`, key, source.allHeaders[key]);
            }
        });
    }
    // Print all the post data
    if (source?.postData) {
        const paramsObj = {};
        switch (normalizeMimeType(source?.postData?.mimeType)) {
            case MediaTypes.URL_ENCODED:
                source.postData.params.forEach((param) => {
                    paramsObj[param.name] = param.value;
                });
                code.push(`${code.var('request')}.body = URI.encode_www_form(${stringifyObject(paramsObj, {
                    indent: options.indent,
                    inlineCharacterLimit: 25,
                })})`);
                break;
            case MediaTypes.JSON:
                code.push(`${code.var('request')}.body = ${stringifyObject(source.postData.jsonObj, {
                    indent: options.indent,
                    inlineCharacterLimit: 25,
                }).replace(/null/g, 'nil')}.to_json`);
                break;
            case MediaTypes.MULTIPART:
                if (source.postData.params) {
                    code.push(`${code.var('form_data')} = [`);
                    source.postData.params.forEach((param) => {
                        code.push(indent, `['${param.name}', '${param.value}'],`);
                    });
                    code.push(']');
                }
                code.push(`${code.var('request')}.set_form(${code.var('form_data')}, '${MediaTypes.MULTIPART}')`);
                break;
            default:
                if (source.postData?.text) {
                    code.push(`${code.var('request')}.body = ${JSON.stringify(source.postData?.text)}`);
                }
        }
    }
    // Print basic auth code if present
    if (source.basicAuth) {
        const { username, password } = source.basicAuth;
        code.push(`${code.var('request')}.basic_auth('${username}', '${password}')`);
    }
    // Print code that makes response
    code
        .blank()
        .push(`${code.var('response')} = ${code.var('http')}.request(${code.var('request')})`)
        .push(`puts ${code.var('response')}.read_body`)
        .blank();
    return code.join();
};
export const info = {
    key: 'native',
    title: 'net::http',
    link: 'http://ruby-doc.org/stdlib-2.2.1/libdoc/net/http/rdoc/Net/HTTP.html',
    description: 'Ruby HTTP client',
};
export default handler;
//# sourceMappingURL=native.js.map