import stringifyObject from 'stringify-object';
import { CodeBuilder } from '../../helpers/code-builder.js';
import { addIndentation, getPreserveTransformer, buildUrlExpression, printUrlVariablesDeclarations, } from '../../helpers/code-helpers.js';
import { Lang } from '../../helpers/constants.js';
import { normalizeMimeType } from '../../../../utils.js';
import { HTTPSnippet } from '../../index.js';
import { MediaTypes } from '../../../../../constants.js';
const handler = function (source, originalOptions, { target, client }) {
    const options = Object.assign({
        indent: '  ',
        showBoilerplate: true,
        level: 1,
    }, originalOptions);
    const { level } = options;
    let includeFS = false;
    const code = new CodeBuilder({
        indentation: options.indent,
        variablesPrefix: options.variablesPrefix,
        capitalize: true,
        lang: Lang.NODEJS,
    });
    if (options.withComments) {
        addComments(code);
    }
    if (options.withImports) {
        code.push("import fetch from 'node-fetch';");
        code.blank();
    }
    if (options.showBoilerplate) {
        code.push('async function run() {');
    }
    const reqOpts = {
        method: source.method.toUpperCase(),
    };
    if (Object.keys(source.headersObj).length) {
        reqOpts.headers = source.headersObj;
    }
    let preserverOriginalAuthorizationHeader = false;
    if (source.securityOAuth2ExtraCalls?.length) {
        const oAuth2PrefixCode = new HTTPSnippet(source.securityOAuth2ExtraCalls?.[0]).convert(target, client, {
            ...options,
            withImports: false,
            withComments: false,
            variablesPrefix: 'oAuth2',
            showBoilerplate: false,
            level: 1,
        });
        code.push(oAuth2PrefixCode);
        code.blank();
        reqOpts.headers = reqOpts.headers || {};
        reqOpts.headers.Authorization = `'Bearer ' + oAuth2Data.access_token`;
        preserverOriginalAuthorizationHeader = true;
    }
    const hasQueryVariables = Object.getOwnPropertyNames(source.queryObj).length;
    if (hasQueryVariables) {
        code
            .push(level, `const ${code.var('query')} = new URLSearchParams(${addIndentation(stringifyObject(source.queryObj, {
            indent: options.indent,
            inlineCharacterLimit: 25,
        }), { level, indent: options.indent, firstLine: false })}).toString();`)
            .blank();
    }
    if (source.postData) {
        switch (normalizeMimeType(source.postData.mimeType)) {
            case MediaTypes.URL_ENCODED:
                reqOpts.body = source.postData.paramsObj
                    ? `new URLSearchParams(${code.var('formData')}).toString()`
                    : source.postData.text;
                if (source.postData.paramsObj) {
                    code
                        .push(level, `const ${code.var('formData')} = ${addIndentation(stringifyObject(source.postData.paramsObj, {
                        indent: options.indent,
                        inlineCharacterLimit: 25,
                    }), { level, firstLine: false })};`)
                        .blank();
                }
                break;
            case MediaTypes.JSON:
                if (source.postData.jsonObj) {
                    reqOpts.body = `JSON.stringify(${addIndentation(stringifyObject(source.postData.jsonObj, {
                        indent: options.indent,
                        inlineCharacterLimit: 25,
                    }), { level, firstLine: false })})`;
                }
                break;
            // TODO: handle this mime type corectly!
            case MediaTypes.MULTIPART:
                // Content type with boundary should be set automatically
                delete reqOpts?.headers?.['Content-Type'];
                if (options.withImports) {
                    code.unshift("import FormData from 'form-data';");
                }
                code.push(level, `const ${code.var('form')} = new FormData();`);
                source.postData.params.forEach(function (param) {
                    if (!param.fileName && !param.fileName && !param.contentType) {
                        code.push(level, "form.append('" + param.name + "','" + param.value + "');");
                        return;
                    }
                    if (param.fileName) {
                        includeFS = true;
                        code.blank();
                        code.push(level, `${code.var('form')}.append('" + param.name + "', fs.createReadStream('" + param.fileName + "'));`);
                    }
                });
                reqOpts.body = code.var('form');
                code.blank();
                break;
            default:
                if (source.postData.text) {
                    reqOpts.body = `\`${addIndentation(source.postData.text, {
                        level: level + 1,
                        indent: options.indent,
                        firstLine: false,
                    }).trim()}\``;
                }
        }
    }
    // construct cookies argument
    if (source.cookies.length) {
        let cookies = '';
        source.cookies.forEach(function (cookie) {
            cookies =
                cookies + encodeURIComponent(cookie.name) + '=' + encodeURIComponent(cookie.value) + '; ';
        });
        cookies = cookies.trim();
        if (reqOpts.headers) {
            reqOpts.headers.cookie = cookies;
        }
        else {
            reqOpts.headers = {};
            reqOpts.headers.cookie = cookies;
        }
    }
    if (source.basicAuth) {
        const { username, password } = source.basicAuth;
        reqOpts.headers = reqOpts.headers || {};
        reqOpts.headers.Authorization = `'Basic ' + Buffer.from('${username}:${password}').toString('base64')`;
        preserverOriginalAuthorizationHeader = true;
    }
    if (includeFS && options.withImports) {
        code.unshift("import fs from 'fs';");
    }
    const isJSON = (reqOpts.headers &&
        reqOpts.headers.Accept &&
        normalizeMimeType(reqOpts.headers.Accept) === MediaTypes.JSON) ||
        normalizeMimeType(source.postData?.mimeType) === MediaTypes.JSON;
    printUrlVariablesDeclarations(source, code, level);
    const URL = buildUrlExpression(source, code);
    code
        .push(level, `const ${code.var('resp')} = await fetch(`)
        .push(level + 1, '`' + URL + (hasQueryVariables ? '?${' + code.var('query') + '}' : '') + '`,')
        .push(level + 1, addIndentation(stringifyObject(reqOpts, {
        indent: options.indent,
        inlineCharacterLimit: 25,
        transform: getPreserveTransformer({
            body: true,
            authorizationHeader: preserverOriginalAuthorizationHeader,
        }),
    }), { level: level + 1, indent: options.indent, firstLine: false }))
        .push(level, ');')
        .blank();
    if (source.allResponseCodes?.includes('204')) {
        code
            .push(level, `if (resp.status === 204) {`)
            .push(level + 1, "console.log('success');")
            .push(level, '} else {');
        code
            .push(level + 1, `const ${code.var('data')} = await ${code.var('resp')}.${isJSON ? 'json()' : 'text()'};`)
            .push(level + 1, `console.log(${code.var('data')});`)
            .push(level, '}');
    }
    else {
        code
            .push(level, `const ${code.var('data')} = await ${code.var('resp')}.${isJSON ? 'json()' : 'text()'};`)
            .push(level, `console.log(${code.var('data')});`);
    }
    if (options.showBoilerplate) {
        code.push('}').blank().push('run();');
    }
    return code.join().replace(/"fs\.createReadStream\(\\"(.+)\\"\)"/, 'fs.createReadStream("$1")');
};
function addComments(code) {
    code.push('/**');
    code.push(' * Requires Node.js >= 14');
    code.push(' *');
    code.push(' * Requires module "node-fetch" >= 2.6.1');
    code.push(' * See here for installation details:');
    code.push(' *   https://www.npmjs.com/package/node-fetch');
    code.push(' */');
    code.blank();
}
export const info = {
    key: 'fetch',
    title: 'Fetch',
    link: 'https://github.com/bitinn/node-fetch',
    description: 'Simplified HTTP node-fetch client',
};
export default handler;
//# sourceMappingURL=fetch.js.map