"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.downloadFileUpload = downloadFileUpload;
exports.cleanupOldFiles = cleanupOldFiles;
exports.removeUploadDirs = removeUploadDirs;
exports.createFileUploadDirectoryName = createFileUploadDirectoryName;
exports.createTempDirectoryForFileUploads = createTempDirectoryForFileUploads;
exports.downloadAllFileUploadsAndSetContext = downloadAllFileUploadsAndSetContext;
exports.downloadFileUploadsAndSetReferenceInContext = downloadFileUploadsAndSetReferenceInContext;
const axios_1 = __importDefault(require("axios"));
const axiosProxyConfig_1 = require("../http/axiosProxyConfig");
const path_1 = __importDefault(require("path"));
const fs = __importStar(require("fs-extra"));
const stream_1 = require("stream");
const loggingProvider_1 = require("../providers/logging/loggingProvider");
const chalk_1 = __importDefault(require("chalk"));
const Globals_1 = require("../Globals");
const logUtils_1 = require("./logUtils");
async function downloadFileUpload(fileUploadUrl, fileUpload, downloadDirectory, mablApiClient) {
    let client;
    if (mablApiClient) {
        client = mablApiClient.httpClient;
    }
    else {
        client = axios_1.default.create(await (0, axiosProxyConfig_1.currentProxyConfig)());
    }
    try {
        const finalDirectory = path_1.default.normalize(`${downloadDirectory}/${fileUpload.id}`);
        try {
            fs.mkdirSync(finalDirectory);
        }
        catch (error) {
            if (!error.message.includes('file already exists')) {
                throw error;
            }
        }
        const finalPath = path_1.default.normalize(`${finalDirectory}/${fileUpload.name}`);
        const writer = fs.createWriteStream(finalPath);
        const response = await client.get(fileUploadUrl, {
            responseType: 'stream',
        });
        if (response.data.pipe) {
            response.data.pipe(writer);
        }
        else if (response.status < 400) {
            if (typeof response.data[Symbol.iterator] === 'function') {
                stream_1.Readable.from(response.data).pipe(writer);
            }
            else {
                stream_1.Readable.from([JSON.stringify(response.data)]).pipe(writer);
            }
        }
        return new Promise((resolve, reject) => {
            writer.on('finish', () => resolve(finalPath));
            writer.on('error', reject);
        });
    }
    catch (error) {
        loggingProvider_1.logger.error(chalk_1.default.red.bold('Error encountered downloading file for File Upload Step replay'));
        throw error;
    }
}
function cleanupOldFiles(ageInMs = 0) {
    try {
        const dir = Globals_1.Globals.getUploadDirectory();
        const prefix = Globals_1.Globals.getUploadDirectoryPrefix();
        fs.readdirSync(dir)
            .filter((file) => file.startsWith(prefix) && uploadDirTooOld(file, ageInMs))
            .forEach((file) => fs.rmSync(`${dir}/${file}`, { recursive: true, force: true }));
    }
    catch (e) {
        const msg = `WARNING: error received when cleaning up old files from a previous test`;
        (0, logUtils_1.logCliOutput)(loggingProvider_1.LogLevel.Warn, msg);
    }
}
function uploadDirTooOld(dirFullPath, ageInMs) {
    const now = Date.now();
    const parts = dirFullPath.split('-');
    return (parts.length === 3 &&
        !Number.isNaN(parseInt(parts[1])) &&
        (ageInMs === 0 || now - parseInt(parts[1]) > ageInMs));
}
function removeUploadDirs(dirFullPath) {
    const MAX_RETRIES = 5;
    const rmOpts = {
        recursive: true,
        maxRetries: MAX_RETRIES,
        force: true,
    };
    fs.rmSync(dirFullPath, rmOpts);
}
function createFileUploadDirectoryName() {
    const dir = Globals_1.Globals.getUploadDirectory();
    const prefix = Globals_1.Globals.getUploadDirectoryPrefix();
    return `${dir}/${prefix}${Date.now()}-`;
}
function createTempDirectoryForFileUploads(fileUploadDirName) {
    return fs.mkdtempSync(fileUploadDirName);
}
async function downloadAllFileUploadsAndSetContext(apiClient, testContext, uploadDirectory, fileUploadReferences) {
    await Promise.all(fileUploadReferences.map(async (fileRef) => {
        const fileUploadUrl = await apiClient.getFileUploadUrl(fileRef.id);
        const finalPathDownloaded = await downloadFileUpload(fileUploadUrl.redirectUrl, fileRef, uploadDirectory, apiClient);
        testContext.setFileUploadReference(fileRef.id, finalPathDownloaded);
    }));
}
async function downloadFileUploadsAndSetReferenceInContext(apiClient, testContext, fileUploadReferences) {
    const uploadDirs = testContext.getFileUploadDirs();
    let uploadDirectoryPath;
    if (uploadDirs.size === 0) {
        const dirName = createFileUploadDirectoryName();
        uploadDirectoryPath = createTempDirectoryForFileUploads(dirName);
        testContext.addFileUploadDir(uploadDirectoryPath);
    }
    else {
        uploadDirectoryPath = uploadDirs.values().next().value;
    }
    if (!uploadDirectoryPath) {
        throw new Error('No upload directory found');
    }
    return downloadAllFileUploadsAndSetContext(apiClient, testContext, uploadDirectoryPath, fileUploadReferences);
}
