import stringifyObject from 'stringify-object';
import { CodeBuilder } from '../../helpers/code-builder.js';
import { HTTPSnippet } from '../../index.js';
import { addIndentation, buildUrlExpression, printUrlVariablesDeclarations, } from '../../helpers/code-helpers.js';
import { normalizeMimeType } from '../../../../utils.js';
import { capitalizeFirst } from '../../../generator.js';
import { Lang } from '../../helpers/constants.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.CSHARPNEWTONSOFT,
    });
    const methodFormatted = formatHttpMethod(source.method);
    if (options.withComments) {
        addComments(code);
    }
    if (options.withWrapper) {
        code.push('using System;');
        code.push('using System.Net.Http;');
        code.push('using System.Threading.Tasks;');
        if (isMimeType(MediaTypes.JSON) || isMimeType(MediaTypes.XML) || source.basicAuth) {
            code.push('using System.Text;');
        }
        if (isMimeType(MediaTypes.URL_ENCODED) || source.securityOAuth2ExtraCalls?.length) {
            code.push('using System.Collections.Generic;');
        }
        if (isMimeType(MediaTypes.JSON) || source.securityOAuth2ExtraCalls?.length) {
            code.push('using Newtonsoft.Json.Linq;');
        }
        if (isOctetStream()) {
            code.push('using System.IO;');
        }
        if (isOctetStream() || source.basicAuth) {
            code.push('using System.Net.Http.Headers;');
        }
        code.blank();
        code.push('public class Program');
        code.push('{');
        code.push(1, 'private readonly IHttpClientFactory _httpClientFactory;');
        code.push(1, 'public static async Task Main(string[] args)');
        code.push(1, '{');
        code.push(2, 'var client = _httpClientFactory.CreateClient();');
    }
    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, 'var oauth2Response = await oauth2Request.Content.ReadAsStringAsync();');
        code.push(2, 'JObject inputJObject = JObject.Parse(oauth2Response);');
        code.push(2, 'var accessToken = inputJObject["access_token"].ToString();');
        code.blank();
    }
    const headers = Object.keys(source.allHeaders).filter((header) => {
        switch (header.toLowerCase()) {
            case 'content-type':
            case 'content-length':
            case 'accept-encoding':
                return false;
            default:
                return true;
        }
    });
    if (headers.length) {
        headers.forEach((key) => {
            code.push(2, 'client.DefaultRequestHeaders.Add("%s", %s);', key, source.securityOAuth2ExtraCalls?.length
                ? '"Bearer " + accessToken'
                : `"${source.allHeaders[key]}"`);
        });
    }
    if (source.basicAuth) {
        const { username, password } = source.basicAuth;
        code.push(2, `var base64String = Convert.ToBase64String(Encoding.ASCII.GetBytes("${username}:${password}"));`);
        code.push(2, 'client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(@"Basic", base64String);');
    }
    if (source.postData) {
        switch (normalizeMimeType(source.postData.mimeType)) {
            case MediaTypes.URL_ENCODED:
                if (source.postData.params) {
                    code.blank();
                    code.push(2, 'List<KeyValuePair<string, string>> postData = new List<KeyValuePair<string, string>>();');
                    source.postData.params.forEach((param) => {
                        code.push(2, 'postData.Add(new KeyValuePair<string, string>("%s", "%s"));', param.name, param.value);
                    });
                    code.blank();
                }
                break;
            case MediaTypes.MULTIPART:
                if (source.postData.params) {
                    code.blank();
                    code.push(2, 'MultipartFormDataContent postData = new MultipartFormDataContent();');
                    source.postData.params.forEach((param) => {
                        code.push(2, 'postData.Add(new StringContent("%s"), "%s");', param.value, param.name);
                    });
                }
                break;
            case MediaTypes.JSON:
                if (source.postData.jsonObj) {
                    code.push(2, `JObject json = JObject.Parse(@"${addIndentation(stringifyObject(source.postData.jsonObj, {
                        indent: options.indent,
                        inlineCharacterLimit: 25,
                    }).replace(/"/g, '""'), { level: 3, firstLine: false })}");`);
                    code.push(2, 'var postData = new StringContent(json.ToString(), Encoding.UTF8, "%s");', source.postData.mimeType);
                }
                break;
            case MediaTypes.XML:
                if (source.postData.text) {
                    source.postData.text
                        .trim()
                        .split('\n')
                        .forEach((item, index) => {
                        const line = (index === 0 ? 'string xml = @"' : '') + item.replace(/"/g, '""');
                        code.push(index === 0 ? 3 : 4, line);
                    });
                    code.push(2, '";');
                    code.push(2, 'var postData = new StringContent(xml, Encoding.UTF8, "%s");', source.postData.mimeType);
                }
                break;
        }
    }
    else if (isOctetStream()) {
        code.push(2, 'var ms = new MemoryStream();');
        code.push(2, 'var postData = new StreamContent(ms);');
        code.push(2, 'postData.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");');
    }
    printUrlVariablesDeclarations(source, code, 3);
    code.push(2, 'var %s = await client.%sAsync(%s%s);', code.var('request'), methodFormatted, buildUrlExpression(source, code), options.withImports
        ? isDataMethod(source.method)
            ? normalizeMimeType(source.postData && source.postData.mimeType) === MediaTypes.URL_ENCODED
                ? ', new FormUrlEncodedContent(postData)'
                : source.method === 'delete'
                    ? ''
                    : (source.postData && source.postData.params) || isOctetStream()
                        ? ', postData'
                        : ', null'
            : ''
        : ', new FormUrlEncodedContent(postData)');
    if (options.withWrapper) {
        code.push(2, 'var response = await request.Content.ReadAsStringAsync();');
        code.blank();
        code.push(2, 'Console.WriteLine(response);');
        code.push(1, '}');
        code.push('}');
    }
    return code.join();
    function isMimeType(mimeType) {
        return source.postData && normalizeMimeType(source.postData.mimeType) === mimeType;
    }
    function isOctetStream() {
        return source.headersObj && source.headersObj['Content-Type'] === MediaTypes.OCTET_STREAM;
    }
};
export const info = {
    key: 'httpclient',
    title: 'HttpClient',
    link: 'https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient',
    description: '.NET Standard HTTP Client',
};
export default handler;
function addComments(code) {
    code.push('/*');
    code.push(' * Requires >= .NET 5');
    code.push(' *');
    code.push(' * Requires package "Newtonsoft.Json" >= 9.01');
    code.push(' * See here for installation details:');
    code.push(' *  https://www.newtonsoft.com/json');
    code.push(' */');
    code.blank();
}
function formatHttpMethod(method) {
    return capitalizeFirst(method.toLowerCase());
}
function isDataMethod(method) {
    const methods = ['POST', 'PUT', 'DELETE', 'PATCH'];
    return method && methods.includes(method.toUpperCase());
}
//# sourceMappingURL=httpclient.js.map