import stringifyObject from 'stringify-object';
import { CodeBuilder } from '../../helpers/code-builder.js';
import { addIndentation, getPreserveTransformer, buildUrlExpression, printUrlVariablesDeclarations, } from '../../helpers/code-helpers.js';
import { normalizeMimeType } from '../../../../utils.js';
import { HTTPSnippet } from '../../index.js';
import { Lang } from '../../helpers/constants.js';
import { MediaTypes } from '../../../../../constants.js';
const handler = function (source, originalOptions, { target, client }) {
    const options = {
        indent: '  ',
        credentials: null,
        ...originalOptions,
    };
    const code = new CodeBuilder({
        indentation: options.indent,
        variablesPrefix: options.variablesPrefix,
        capitalize: true,
        lang: Lang.JAVASCRIPT,
    });
    const reqOpts = {
        method: source.method.toUpperCase(),
    };
    // TODO: Should we also add cookies here (like in node.js fetch)?
    if (Object.keys(source.headersObj).length) {
        reqOpts.headers = source.headersObj;
    }
    let preserverOriginalAuthorizationHeader = false;
    if (options.withComments) {
        addComments(code);
    }
    if (source.securityOAuth2ExtraCalls?.length) {
        const oAuth2PrefixCode = new HTTPSnippet(source.securityOAuth2ExtraCalls?.[0]).convert(target, client, { ...options, withImports: false, withComments: false, variablesPrefix: 'oAuth2' });
        code.push(oAuth2PrefixCode);
        code.blank();
        reqOpts.headers = reqOpts.headers || {};
        reqOpts.headers.Authorization = `'Bearer ' + oAuth2Data.access_token`;
        preserverOriginalAuthorizationHeader = true;
    }
    if (options.credentials !== null) {
        reqOpts.credentials = options.credentials;
    }
    const hasQueryVariables = Object.getOwnPropertyNames(source.queryObj).length;
    if (hasQueryVariables) {
        code
            .push(`const ${code.var('query')} = new URLSearchParams(${stringifyObject(source.queryObj, {
            indent: options.indent,
            inlineCharacterLimit: 25,
        })}).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(`const ${code.var('formData')} = ${addIndentation(stringifyObject(source.postData.paramsObj, {
                        indent: options.indent,
                        inlineCharacterLimit: 25,
                    }), { level: 0, 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: 1, firstLine: false })})`;
                }
                break;
            // TODO: handle this mime type corectly!
            case MediaTypes.MULTIPART:
                code.push(`const ${code.var('form')} = new FormData();`);
                // Content type with boundary should be set automatically
                delete reqOpts?.headers?.['Content-Type'];
                source.postData.params.forEach(function (param) {
                    code.push(`${code.var('form')}.append(%s, %s);`, JSON.stringify(param.name), JSON.stringify(param.value || param.fileName || ''));
                });
                reqOpts.body = code.var('form');
                code.blank();
                break;
            default:
                if (source.postData.text) {
                    reqOpts.body = `\`${addIndentation(source.postData.text, {
                        level: 2,
                        indent: options.indent,
                        firstLine: false,
                    }).trim()}\``;
                }
        }
    }
    const isJSON = (reqOpts.headers &&
        reqOpts.headers.Accept &&
        normalizeMimeType(reqOpts.headers.Accept) === MediaTypes.JSON) ||
        normalizeMimeType(source.postData?.mimeType) === MediaTypes.JSON;
    if (source.basicAuth) {
        const { username, password } = source.basicAuth;
        reqOpts.headers = reqOpts.headers || {};
        reqOpts.headers.Authorization = `'Basic ' + btoa('${username}:${password}')`;
        preserverOriginalAuthorizationHeader = true;
    }
    printUrlVariablesDeclarations(source, code);
    const URL = buildUrlExpression(source, code);
    code
        .push(`const ${code.var('resp')} = await fetch(`)
        .push(1, '`' + URL + (hasQueryVariables ? '?${' + code.var('query') + '}' : '') + '`,')
        .push(addIndentation(stringifyObject(reqOpts, {
        indent: options.indent,
        inlineCharacterLimit: 25,
        transform: getPreserveTransformer({
            body: true,
            authorizationHeader: preserverOriginalAuthorizationHeader,
        }),
    }), { level: 1, indent: options.indent }))
        .push(');')
        .blank();
    if (source.allResponseCodes?.includes('204')) {
        code.push(`if (resp.status === 204) {`).push(1, "console.log('success');").push('} else {');
        code
            .push(1, `const ${code.var('data')} = await ${code.var('resp')}.${isJSON ? 'json()' : 'text()'};`)
            .push(1, `console.log(${code.var('data')});`)
            .push('}');
    }
    else {
        code
            .push(`const ${code.var('data')} = await ${code.var('resp')}.${isJSON ? 'json()' : 'text()'};`)
            .push(`console.log(${code.var('data')});`);
    }
    return code.join();
};
function addComments(code) {
    code.push('/**');
    code.push(' * Requires ES8-compatible browser: https://caniuse.com/async-functions');
    code.push(' */');
    code.blank();
}
export const info = {
    key: 'fetch',
    title: 'fetch',
    link: 'https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch',
    description: 'Perform asynchronous HTTP requests with the Fetch API',
};
export default handler;
//# sourceMappingURL=fetch.js.map