"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;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.PROCESSED_DIR_NAME = void 0;
exports.createFilenameMatcher = createFilenameMatcher;
exports.getAwaitDownloadTimeout = getAwaitDownloadTimeout;
exports.awaitDownload = awaitDownload;
exports.getLatestFile = getLatestFile;
exports.moveDownloadedFileToProcessed = moveDownloadedFileToProcessed;
const path = __importStar(require("path"));
const fs = __importStar(require("fs"));
const fsExtra = __importStar(require("fs-extra"));
const util = __importStar(require("util"));
const sleep_1 = require("./sleep");
const stepValidation_1 = require("../core/entityValidation/stepValidation");
const AWAIT_DOWNLOAD_MAX_TIMEOUT_MILLIS = 60_000;
const FILE_MIN_STABLE_TIME_MILLIS = 3000;
const AWAIT_DOWNLOAD_POLLING_INTERVAL_MILLISECONDS = 500;
exports.PROCESSED_DIR_NAME = 'Processed';
function createFilenameMatcher(pattern, mode) {
    if (!pattern) {
        return () => true;
    }
    const lowerPattern = pattern.normalize('NFC').toLowerCase();
    switch (mode) {
        case 'contains':
            return (fullPath) => path
                .basename(fullPath)
                .normalize('NFC')
                .toLowerCase()
                .includes(lowerPattern);
        case 'starts_with':
            return (fullPath) => path
                .basename(fullPath)
                .normalize('NFC')
                .toLowerCase()
                .startsWith(lowerPattern);
        case 'ends_with':
            return (fullPath) => path
                .basename(fullPath)
                .normalize('NFC')
                .toLowerCase()
                .endsWith(lowerPattern);
        case 'matches_regex': {
            let regex;
            try {
                regex = (0, stepValidation_1.parseRegexPattern)(pattern, { defaultFlags: 'i' });
            }
            catch {
                return () => false;
            }
            return (fullPath) => regex.test(path.basename(fullPath).normalize('NFC'));
        }
        case 'equals':
        default:
            return (fullPath) => fullPath.normalize('NFC').toLowerCase().endsWith(lowerPattern);
    }
}
function getAwaitDownloadTimeout() {
    return AWAIT_DOWNLOAD_MAX_TIMEOUT_MILLIS;
}
async function awaitDownload(downloadDirectory, fileMatcher, timeoutMillis = getAwaitDownloadTimeout()) {
    const startTime = Date.now();
    let foundDownloadPath;
    let downloadComplete = false;
    while (Date.now() - timeoutMillis < startTime && !downloadComplete) {
        const latestFile = await getLatestFile(downloadDirectory, fileMatcher);
        if (latestFile) {
            downloadComplete = true;
            foundDownloadPath = latestFile;
        }
        else {
            await (0, sleep_1.sleep)(AWAIT_DOWNLOAD_POLLING_INTERVAL_MILLISECONDS);
        }
    }
    return foundDownloadPath;
}
async function getLatestFile(downloadDirectory, fileMatcher) {
    const matchFn = typeof fileMatcher === 'string'
        ? (fullPath) => fullPath
            .normalize('NFC')
            .toLowerCase()
            .endsWith(fileMatcher.normalize('NFC').toLowerCase())
        : fileMatcher;
    const readDirectoryAsync = util.promisify(fs.readdir);
    const filesInDownloadDir = await readDirectoryAsync(downloadDirectory);
    let latestFileTime = 0;
    let latestFilePath;
    filesInDownloadDir.forEach((fileName) => {
        const fullPath = `${downloadDirectory}/${fileName}`;
        try {
            const stats = fs.statSync(path.normalize(fullPath));
            if (stats.isFile() &&
                stats.ctimeMs > latestFileTime &&
                Date.now() - stats.mtimeMs >= FILE_MIN_STABLE_TIME_MILLIS &&
                !fullPath.includes('.crDownload') &&
                matchFn(fullPath)) {
                latestFileTime = stats.ctimeMs;
                latestFilePath = fullPath;
            }
        }
        catch {
        }
    });
    return latestFilePath;
}
function moveDownloadedFileToProcessed(downloadDirectory, fileName, finalDirectoryName) {
    const processedDirectory = path.join(downloadDirectory, exports.PROCESSED_DIR_NAME);
    const finalProcessedDirectory = finalDirectoryName
        ? path.join(processedDirectory, finalDirectoryName)
        : processedDirectory;
    const sourceLocation = path.join(downloadDirectory, fileName);
    const destinationLocation = path.join(finalProcessedDirectory, fileName);
    fsExtra.ensureDirSync(processedDirectory);
    fsExtra.ensureDirSync(finalProcessedDirectory);
    fsExtra.moveSync(sourceLocation, destinationLocation, { overwrite: true });
}
