import { CodeBuilder } from '../../helpers/code-builder.js';
import { HTTPSnippet } from '../../index.js';
import { isEmptyObject, normalizeMimeType } from '../../../../utils.js';
import { capitalizeFirst } from '../../../generator.js';
import { Lang } from '../../helpers/constants.js';
import { buildUrlExpression, printUrlVariablesDeclarations } from '../../helpers/code-helpers.js';
import { MediaTypes } from '../../../../../constants.js';
const handler = function (source, originalOptions, { target, client }) {
    const options = Object.assign({ indent: '  ', withWrapper: true }, originalOptions);
    const code = new CodeBuilder({
        indentation: options.indent,
        variablesPrefix: options.variablesPrefix,
        capitalize: true,
        lang: Lang.JAVA8,
    });
    const methodFormatted = formatHttpMethod(source.method);
    if (options.withComments) {
        addComments(code);
    }
    if (options.withImports) {
        addImports(code, source);
    }
    if (options.withWrapper) {
        code.push('public class App {');
        code.push(1, 'public static void main(String[] args ) throws java.io.IOException {');
        code.push(2, 'HttpClient httpClient = HttpClientBuilder.create().build();');
        code.blank();
    }
    if (source.securityOAuth2ExtraCalls?.length) {
        const oAuth2PrefixCode = new HTTPSnippet(source.securityOAuth2ExtraCalls?.[0]).convert(target, client, {
            ...options,
            withImports: false,
            withWrapper: false,
            withComments: false,
            variablesPrefix: 'oauth2',
        });
        code.push(oAuth2PrefixCode);
        code.push(2, 'JSONObject %s = new JSONObject(EntityUtils.toString(httpClient.execute(%s).getEntity()));', 'oauth2Response', 'oauth2Request');
        code.push(2, 'String accessToken = %s.getString("access_token");', 'oauth2Response');
        code.blank();
    }
    printUrlVariablesDeclarations(source, code, 2);
    const URL = buildUrlExpression(source, code);
    code.push(2, `%s ${code.var('request')} = new %s(%s);`, methodFormatted, methodFormatted, URL);
    const headers = Object.keys(source.allHeaders);
    if (headers.length && !(source.postData && source.postData.mimeType == MediaTypes.MULTIPART)) {
        headers.forEach((key) => {
            code.push(2, '%s.setHeader("%s", %s);', code.var('request'), key, source.securityOAuth2ExtraCalls?.length
                ? '"Bearer " + accessToken'
                : `"${source.allHeaders[key]}"`);
        });
    }
    if (source.basicAuth) {
        const { username, password } = source.basicAuth;
        code.push(2, `String encodedString = Base64.getEncoder().encodeToString("${username}:${password}".getBytes());`);
        code.push(2, '%s.setHeader("%s", "%s"+encodedString);', code.var('request'), 'Authorization', 'Basic ');
    }
    if (source.postData) {
        switch (normalizeMimeType(source.postData.mimeType)) {
            case MediaTypes.URL_ENCODED:
                if (source.postData.params) {
                    code.blank();
                    code.push(2, 'List<NameValuePair> params = new ArrayList<NameValuePair>();');
                    source.postData.params.forEach((param) => {
                        code.push(2, 'params.add(new BasicNameValuePair("%s", "%s"));', param.name, param.value);
                    });
                    code.push(2, '%s.setEntity(new UrlEncodedFormEntity(params));', code.var('request'));
                    code.blank();
                }
                break;
            case MediaTypes.MULTIPART:
                if (source.postData.params) {
                    code.push(2, 'MultipartEntity reqEntity = new MultipartEntity();');
                    source.postData.params.forEach((param) => {
                        code.push(2, 'reqEntity.addPart("%s", %s);', param.name, isString(param.value) ? `new StringBody("${param.value}")` : param.value);
                    });
                    code.push(2, '%s.setEntity(reqEntity);', code.var('request'));
                }
                break;
            case MediaTypes.JSON:
                if (source.postData.jsonObj) {
                    code.push(2, 'JSONObject payload = new JSONObject();');
                    for (const [key, value] of Object.entries(source.postData.jsonObj)) {
                        if (Array.isArray(value)) {
                            code.push(2, 'payload.put("%s", new JSONArray()', key);
                            value.forEach((item) => {
                                if (isObject(item)) {
                                    code.push(3, '.put(new JSONObject()');
                                    iterateObject(item, 4);
                                    code.push(3, ')');
                                }
                                else {
                                    code.push(3, '.put(%s)', formatValue(item));
                                }
                            });
                            code.push(2, ');');
                        }
                        else if (isObject(value)) {
                            code.push(2, 'payload.put("%s", new JSONObject()%s', key, isEmptyObject(value) ? ');' : '');
                            iterateObject(value, 3);
                            if (!isEmptyObject(value)) {
                                code.push(2, ');');
                            }
                        }
                        else {
                            code.push(2, 'payload.put("%s", %s);', key, formatValue(value));
                        }
                    }
                    code.push(2, '%s.setEntity(new StringEntity(payload.toString()));', code.var('request'));
                }
                break;
            case MediaTypes.XML:
                if (source.postData.text) {
                    code.push(2, 'String payload = String.join("\\n"');
                    source.postData.text
                        .trim()
                        .split('\n')
                        .forEach((item) => {
                        const line = item.replace(/"/g, '\\"');
                        code.push(3, `"${line}", `);
                    });
                    code.push(2, ');');
                    code.push(2, '%s.setEntity(new StringEntity(payload));', code.var('request'));
                }
                break;
        }
    }
    // TODO: Add default case to handle unsupported mimeType or data type
    if (options.withWrapper) {
        code.push(2, `String ${code.var('response')} = EntityUtils.toString(httpClient.execute(request).getEntity());`);
        code.blank();
        code.push(2, 'System.out.println(response);');
        code.push(1, '}');
        code.push('}');
    }
    return code.join();
    function iterateObject(obj, indent) {
        for (const [key, value] of Object.entries(obj)) {
            if (isObject(value)) {
                code.push(indent, '.put("%s", new JSONObject()', key);
                iterateObject(value, indent + 1);
                code.push(indent, ')');
            }
            else {
                code.push(indent, '.put("%s", %s)', key, formatValue(value));
            }
        }
    }
};
export const info = {
    key: 'apachehttp',
    title: 'Apache http',
    link: 'https://hc.apache.org/httpcomponents-client-4.5.x/',
    description: 'Apache HttpClient',
};
export default handler;
function addComments(code) {
    code.push('/**');
    code.push(' * Requires JDK >= 8');
    code.push(' *');
    code.push(' * Requires Apache HttpComponents Client >= 4.3.5');
    code.push(' * See here for installation details:');
    code.push(' *   https://search.maven.org/artifact/org.apache.httpcomponents/httpcomponents-client');
    code.push(' *');
    code.push(' * Requires package "junit4"');
    code.push(' * See here for installation details:');
    code.push(' *   https://junit.org/junit4');
    code.push(' *');
    code.push(' * Requires package "org.json" >= 20180130');
    code.push(' * See here for installation details:');
    code.push(' *   https://search.maven.org/artifact/org.json/json');
    code.push(' */');
    code.blank();
}
function addImports(code, source) {
    code.push('import org.apache.http.util.EntityUtils;');
    code.push('import org.apache.http.NameValuePair;');
    code.push('import org.apache.http.client.HttpClient;');
    code.push('import org.apache.http.client.entity.UrlEncodedFormEntity;');
    if (source.method) {
        addHttpMethodImport(code, source.method);
    }
    if (source.securityOAuth2ExtraCalls?.length &&
        source.securityOAuth2ExtraCalls?.[0].method.toLowerCase() !== source.method.toLowerCase()) {
        addHttpMethodImport(code, source.securityOAuth2ExtraCalls?.[0].method);
    }
    code.push('import org.apache.http.impl.client.HttpClientBuilder;');
    code.push('import org.apache.http.message.BasicNameValuePair;');
    code.push('import org.apache.http.entity.StringEntity;');
    code.push('import org.json.JSONObject;');
    code.push('import org.json.JSONArray;');
    code.push('import java.util.ArrayList;');
    code.push('import java.util.List;');
    code.push('import org.apache.http.entity.mime.MultipartEntity;');
    code.push('import org.apache.http.entity.mime.content.StringBody;');
    if (source.basicAuth) {
        code.push('import java.util.Base64;');
    }
    code.blank();
}
function addHttpMethodImport(code, method) {
    const methodFormatted = formatHttpMethod(method);
    code.push(`import org.apache.http.client.methods.${methodFormatted};`);
}
function formatHttpMethod(method) {
    return 'Http' + capitalizeFirst(method.toLowerCase());
}
function isString(str) {
    return Object.prototype.toString.call(str) === '[object String]';
}
function isObject(obj) {
    const type = typeof obj;
    return type === 'function' || (type === 'object' && !!obj);
}
function formatValue(value) {
    if (isString(value))
        return JSON.stringify(value);
    else if (value == null)
        return 'JSONObject.NULL';
    else
        return value;
}
//# sourceMappingURL=apachehttp.js.map