/* eslint-disable @typescript-eslint/no-unused-vars */
import { PostmanTransformer, dataValue, paramValue } from './PostmanTransformer.js';
import { HttpProject, Kind as HttpProjectKind } from '../HttpProject.js';
import { Environment } from '../Environment.js';
import { Thing } from '../Thing.js';
/**
 * Transformer for Postman backup file.
 */
export class PostmanBackupTransformer extends PostmanTransformer {
    async transform() {
        const raw = this[dataValue];
        const result = [];
        if (!raw.collections) {
            return result;
        }
        for (const collection of raw.collections) {
            const project = await this.transformCollection(collection);
            result.push(project);
        }
        return result;
    }
    async transformCollection(collection) {
        const { folders_order, order } = collection;
        const project = this.createProject(collection);
        this.setProjectVariables(project, collection);
        if (Array.isArray(folders_order)) {
            for (const id of folders_order) {
                await this.addFolder(project, collection, id);
            }
        }
        if (Array.isArray(order)) {
            for (const id of order) {
                await this.addRequest(project, collection, id);
            }
        }
        return project;
    }
    createProject(collection) {
        const { description, id, name } = collection;
        const init = {
            kind: HttpProjectKind,
            definitions: {},
            info: Thing.fromName(name).toJSON(),
            items: [],
            key: id,
        };
        if (description) {
            init.info.description = description;
        }
        const project = new HttpProject(init);
        return project;
    }
    setProjectVariables(project, collection) {
        const { variables } = collection;
        if (!Array.isArray(variables)) {
            return;
        }
        const env = Environment.fromName('Default');
        project.addEnvironment(env);
        variables.forEach((param) => {
            const { disabled = false, key, value } = param;
            const parsed = this.ensureVariablesSyntax(value);
            const created = env.addVariable(key, parsed);
            created.enabled = !disabled;
        });
    }
    async addFolder(current, collection, id) {
        const { folders } = collection;
        const folder = folders?.find((i) => i.id === id);
        if (!folder) {
            this.addLog('warning', `Folder ${id} not found in the collection.`);
            return;
        }
        const created = current.addFolder(folder.name);
        if (folder.description) {
            created.info.description = folder.description;
        }
        if (Array.isArray(folder.folders_order)) {
            for (const id of folder.folders_order) {
                await this.addFolder(created, collection, id);
            }
        }
        if (Array.isArray(folder.order)) {
            for (const id of folder.order) {
                await this.addRequest(created, collection, id);
            }
        }
    }
    async addRequest(current, collection, id) {
        const { requests } = collection;
        const request = requests?.find((i) => i.id === id);
        if (!request) {
            this.addLog('warning', `Request ${id} not found in the collection.`);
            return;
        }
        const name = request.name || 'unnamed';
        let url = request.url || 'http://';
        url = this.ensureVariablesSyntax(url);
        let method = request.method || 'GET';
        method = this.ensureVariablesSyntax(method);
        let headers = request.headers || '';
        headers = this.ensureVariablesSyntax(headers);
        let createdTime = Number(request.time);
        if (Number.isNaN(createdTime)) {
            createdTime = Date.now();
        }
        const created = current.addRequest(url);
        created.info.name = name;
        if (request.description) {
            created.info.description = request.description;
        }
        created.expects.method = method;
        if (headers) {
            created.expects.headers = headers;
        }
        await this.addRequestBody(created, request);
    }
    async addRequestBody(created, request) {
        switch (request.dataMode) {
            case 'urlencoded':
                return this.addUrlencodedBody(created, request);
            case 'binary':
                return this.addBinaryBody(created, request);
            case 'params':
                return this.addParamsBody(created, request);
            case 'raw':
                return this.addRawBody(created, request);
        }
    }
    async addUrlencodedBody(created, request) {
        if (!Array.isArray(request.data)) {
            return;
        }
        const data = request.data;
        const body = data.map((i) => `${paramValue(i.key)}=${paramValue(i.value)}`).join('&');
        await created.expects.writePayload(body);
    }
    async addBinaryBody(created, request) {
        // Postman sets the `rawModeData` property with the path to the file
        // but not data itself. Because of that this method is a stub that can be extended
        // by particular implementation (like node, CLI).
    }
    async addParamsBody(created, request) {
        // "params" is Postman's FormData implementation.
        // Similarly to the `addBinaryBody()`, file parts carry no data.
        // Override the `addParamsFilePart()` to handle file read from the filesystem.
        if (!Array.isArray(request.data)) {
            return;
        }
        const data = request.data;
        const body = [];
        for (const part of data) {
            if (part.type === 'text') {
                await this.addParamsTextPart(body, part);
            }
            else if (part.type === 'file') {
                await this.addParamsFilePart(body, part);
            }
        }
        created.expects.payload = {
            type: 'formdata',
            data: body,
        };
    }
    async addParamsTextPart(body, param) {
        const { key, value, enabled = true } = param;
        body.push({
            isFile: false,
            name: key,
            value,
            enabled,
        });
    }
    async addParamsFilePart(body, param) {
        // Postman sets the `value` property with the path to the file
        // but not data itself. Because of that this method is a stub that can be extended
        // by particular implementation (like node, CLI).
    }
    async addRawBody(created, request) {
        const { rawModeData, data } = request;
        if (rawModeData && typeof rawModeData === 'string') {
            await created.expects.writePayload(rawModeData);
        }
        else if (data && typeof data === 'string') {
            await created.expects.writePayload(data);
        }
    }
}
//# sourceMappingURL=PostmanBackupTransformer.js.map