"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PackageFiles = void 0;
const tslib_1 = require("tslib");
const is_1 = tslib_1.__importDefault(require("@sindresorhus/is"));
const logger_1 = require("../../logger");
const clone_1 = require("../../util/clone");
class PackageFiles {
    static data = new Map();
    static add(baseBranch, packageFiles) {
        logger_1.logger.debug({ baseBranch }, `PackageFiles.add() - Package file saved for base branch`);
        this.data.set(baseBranch, packageFiles);
    }
    static clear() {
        logger_1.logger.debug('PackageFiles.clear() - Package files deleted');
        this.data.clear();
    }
    /**
     * Truncates the detected dependencies' section until it fits the available space
     * i.e. It has length smaller than maxLength.
     * This does not mutate the original PackageFiles data
     * Note:  setHeader=false is used for testing purposes only
     *        Mainly for comparing truncated and non-truncated markdown
     * @param maxLength
     * @param setHeader
     */
    static getDashboardMarkdown(maxLength, setHeader = true) {
        const note = '> **Note**\n> Detected dependencies section has been truncated\n';
        const title = `## Detected dependencies\n\n`;
        // exclude header length from the available space
        const maxHeaderLen = setHeader ? (title + note).length : 0;
        const mdMaxLength = maxLength - maxHeaderLen;
        let md;
        let header = '';
        let removed = false;
        let truncated = false;
        const data = new Map((0, clone_1.clone)(Array.from(this.data)));
        // filter all deps with skip reason
        for (const managers of [...data.values()].filter(is_1.default.truthy)) {
            for (const files of Object.values(managers).filter(is_1.default.truthy)) {
                for (const file of files.filter((f) => is_1.default.truthy(f.deps))) {
                    file.deps = file.deps.filter(is_1.default.truthy).filter((d) => !d.skipReason);
                }
            }
        }
        do {
            // shorten markdown until it fits
            md = PackageFiles.getDashboardMarkdownInternal(data);
            if (md.length > mdMaxLength) {
                // truncate data
                removed = PackageFiles.pop(data);
            }
            if (removed) {
                truncated = true; // used to set the truncation Note
            }
        } while (removed && md.length > mdMaxLength);
        header += title;
        header += truncated ? note : '';
        return (setHeader ? header : '') + md;
    }
    /**
     * Generates the "detected dependencies" markdown
     * @param data
     */
    static getDashboardMarkdownInternal(data) {
        const none = 'None detected\n\n';
        const pad = data.size > 1; // padding condition for a multi base branch repo
        let deps = '';
        for (const [branch, packageFiles] of data) {
            deps += pad
                ? `<details><summary>Branch ${branch}</summary>\n<blockquote>\n\n`
                : '';
            if (packageFiles === null) {
                deps += none;
                deps += pad ? '</blockquote>\n</details>\n\n' : '';
                continue;
            }
            const managers = Object.keys(packageFiles);
            if (managers.length === 0) {
                deps += none;
                deps += pad ? '</blockquote>\n</details>\n\n' : '';
                continue;
            }
            for (const manager of managers) {
                deps += `<details><summary>${manager}</summary>\n<blockquote>\n\n`;
                for (const packageFile of packageFiles[manager]) {
                    deps += `<details><summary>${packageFile.packageFile}</summary>\n\n`;
                    for (const dep of packageFile.deps) {
                        const ver = dep.currentValue;
                        const digest = dep.currentDigest;
                        const version = ver && digest ? `${ver}@${digest}` : `${digest ?? ver}`;
                        // TODO: types (#22198)
                        deps += ` - \`${dep.depName} ${version}\`\n`;
                    }
                    deps += '\n</details>\n\n';
                }
                deps += `</blockquote>\n</details>\n\n`;
            }
            deps += pad ? '</blockquote>\n</details>\n\n' : '';
        }
        return deps;
    }
    /**
     * Removes the last dependency/entry in the PackageFiles data
     * i.e. the last line in the tobe generated detected dependency section
     * @param data
     * @Returns true if anything that translates to a markdown written line was deleted
     *          otherwise false is returned
     */
    static pop(data) {
        // get detected managers list of the last listed base branch
        const [branch, managers] = Array.from(data).pop() ?? [];
        if (!branch) {
            return false;
        }
        // delete base branch listing if it has no managers left
        if (!managers || is_1.default.emptyObject(managers)) {
            return data.delete(branch);
        }
        // get all manifest files for the last listed manager
        const [manager, packageFiles] = Object.entries(managers).pop();
        // delete current manager if it has no manifest files left
        if (!packageFiles || is_1.default.emptyArray(packageFiles)) {
            return delete managers[manager];
        }
        // delete manifest file if it has no deps left
        const len = packageFiles.length - 1;
        if (is_1.default.emptyArray(packageFiles[len].deps)) {
            return !!packageFiles.pop();
        }
        // remove the last listed dependency
        return !!packageFiles[len].deps.pop();
    }
}
exports.PackageFiles = PackageFiles;
//# sourceMappingURL=package-files.js.map