import { normalizeMimeType, unescapeServerVariables } from '../../utils.js';
import { MediaTypes } from '../../../constants.js';
import targets from './targets/index.js';
import reducer from './helpers/reducer.js';
import { queryString } from '../../../utils/index.js';
import { urlParse } from '../../../utils/url.js';
export class HTTPSnippet {
    request;
    constructor(data) {
        const input = { ...data };
        // prep the main container
        this.request = this.prepare({
            ...input,
            // add optional properties to make validation successful
            httpVersion: input.httpVersion || 'HTTP/1.1',
            queryString: input.queryString || [],
            headers: input.headers || [],
            cookies: input.cookies || [],
            postData: input.postData
                ? {
                    ...input.postData,
                    jsonObj: undefined,
                    paramsObj: undefined,
                }
                : undefined,
            bodySize: 0,
            headersSize: 0,
            queryObj: {},
            headersObj: {},
            cookiesObj: {},
            allHeaders: {},
            uriObj: {},
            fullUrl: '',
            pathParameters: input.pathParameters || {},
            serverVariables: input.serverVariables || {},
        });
    }
    prepare(request) {
        // construct query objects
        if (request.queryString && request.queryString.length) {
            request.queryObj = request.queryString.reduce(reducer, {});
        }
        // construct headers objects
        if (request.headers && request.headers.length) {
            const http2VersionRegex = /^HTTP\/2/;
            request.headersObj = request.headers.reduce(function (headers, header) {
                let headerName = header.name;
                if (request.httpVersion.match(http2VersionRegex)) {
                    headerName = headerName.toLowerCase();
                }
                headers[headerName] = header.value;
                return headers;
            }, {});
        }
        // construct headers objects
        if (request.cookies && request.cookies.length) {
            request.cookiesObj = request.cookies.reduceRight(function (cookies, cookie) {
                cookies[cookie.name] = cookie.value;
                return cookies;
            }, {});
        }
        // construct Cookie header
        const cookies = request.cookies.map(function (cookie) {
            return encodeURIComponent(cookie.name) + '=' + encodeURIComponent(cookie.value);
        });
        if (cookies.length) {
            request.allHeaders.cookie = cookies.join('; ');
        }
        if (request.postData) {
            switch (normalizeMimeType(request.postData.mimeType)) {
                case 'multipart/mixed':
                case 'multipart/related':
                case MediaTypes.MULTIPART:
                case 'multipart/alternative':
                    break;
                case MediaTypes.URL_ENCODED:
                    if (!request.postData?.params) {
                        request.postData.text = '';
                    }
                    else {
                        request.postData.paramsObj = request.postData.params.reduce(reducer, {});
                        // always overwrite
                        request.postData.text = queryString.stringify(request.postData.paramsObj);
                    }
                    break;
                case 'text/json':
                case 'text/x-json':
                case MediaTypes.JSON:
                case 'application/x-json':
                    if (request.postData.text) {
                        try {
                            request.postData.jsonObj = JSON.parse(request.postData.text);
                        }
                        catch {
                            // force back to text/plain
                            // if headers have proper content-type value, then this should also work
                            request.postData.mimeType = 'text/plain';
                        }
                    }
                    break;
            }
        }
        // create allHeaders object
        request.allHeaders = Object.assign(request.allHeaders, request.headersObj);
        // deconstruct the uri
        request.uriObj = urlParse(request.url, true);
        if (!request.uriObj) {
            return {
                ...request,
                uriObj: {
                    protocol: '',
                    path: '',
                    queryObj: {},
                    query: {},
                },
            };
        }
        // update the uri object
        if (request.queryObj) {
            for (const [key, value] of Object.entries(request.queryObj)) {
                if (!request.uriObj.searchParams.has(key, value)) {
                    request.uriObj.searchParams.set(key, value);
                }
            }
        }
        request.uriObj.query = Object.fromEntries(request.uriObj.searchParams.entries());
        // merge all possible queryString values
        request.queryObj = request.uriObj.query;
        // reset uriObj values for a clean url
        request.uriObj.path = request.uriObj.pathname = unescapeServerVariables(request.uriObj.pathname);
        const cleanUri = new URL(request.uriObj.toString());
        cleanUri.search = '';
        // keep the base url clean of queryString
        request.url = unescapeServerVariables(cleanUri.toString());
        if (request.uriObj.search) {
            request.uriObj.path = request.uriObj.pathname + '?' + request.uriObj.search;
        }
        // construct a full url
        request.fullUrl = unescapeServerVariables(request.uriObj.toString());
        return request;
    }
    convert(target, client, opts) {
        if (!opts && client) {
            opts = client;
        }
        const func = this._matchTarget(target, client);
        if (func) {
            const results = func(this.request, opts, { target, client });
            return results.length === 1 ? results[0] : results;
        }
        throw new Error('Cannot match target');
    }
    _matchTarget(target, client) {
        // does it exist?
        if (!Object.prototype.hasOwnProperty.call(targets, target)) {
            return false;
        }
        // shorthand
        if (typeof client === 'string' && typeof targets[target][client] === 'function') {
            return targets[target][client];
        }
        // default target
        return targets[target][targets[target].info.default];
    }
}
//# sourceMappingURL=index.js.map