"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateCommitFingerprintConfig = generateCommitFingerprintConfig;
exports.canSkipBranchUpdateCheck = canSkipBranchUpdateCheck;
exports.syncBranchState = syncBranchState;
exports.writeUpdates = writeUpdates;
const tslib_1 = require("tslib");
const is_1 = tslib_1.__importDefault(require("@sindresorhus/is"));
const logger_1 = require("../../../logger");
const manager_1 = require("../../../modules/manager");
const scm_1 = require("../../../modules/platform/scm");
const repository_1 = require("../../../util/cache/repository");
const fingerprint_1 = require("../../../util/fingerprint");
const set_branch_commit_1 = require("../../../util/git/set-branch-commit");
const limits_1 = require("../../global/limits");
const branch_1 = require("../update/branch");
const fingerprint_fields_1 = require("./fingerprint-fields");
const limits_2 = require("./limits");
function generateCommitFingerprintConfig(branch) {
    const res = branch.upgrades.map((upgrade) => {
        const filteredUpgrade = {};
        for (const field of fingerprint_fields_1.upgradeFingerprintFields) {
            // TS cannot narrow the type here
            // I am not sure if this is the best way suggestions welcome
            if (field !== 'env' && is_1.default.string(upgrade[field])) {
                filteredUpgrade[field] = upgrade[field];
            }
            else if (is_1.default.plainObject(upgrade[field])) {
                filteredUpgrade.env = upgrade[field];
            }
        }
        return filteredUpgrade;
    });
    return res;
}
function canSkipBranchUpdateCheck(branchState, commitFingerprint) {
    if (!branchState.commitFingerprint) {
        logger_1.logger.trace('branch.isUpToDate(): no fingerprint');
        return false;
    }
    if (commitFingerprint !== branchState.commitFingerprint) {
        logger_1.logger.debug('branch.isUpToDate(): needs recalculation');
        return false;
    }
    logger_1.logger.debug('branch.isUpToDate(): using cached result "true"');
    return true;
}
async function syncBranchState(branchName, baseBranch) {
    logger_1.logger.debug('syncBranchState()');
    const branchSha = await scm_1.scm.getBranchCommit(branchName);
    const baseBranchSha = await scm_1.scm.getBranchCommit(baseBranch);
    const cache = (0, repository_1.getCache)();
    cache.branches ??= [];
    const { branches: cachedBranches } = cache;
    let branchState = cachedBranches.find((br) => br.branchName === branchName);
    if (!branchState) {
        logger_1.logger.debug('syncBranchState(): Branch cache not found, creating minimal branchState');
        // create a minimal branch state
        branchState = {
            branchName,
            sha: branchSha,
            baseBranch,
            baseBranchSha,
        };
        cachedBranches.push(branchState);
    }
    // if base branch name has changed invalidate cached isModified state
    if (baseBranch !== branchState.baseBranch) {
        logger_1.logger.debug('syncBranchState(): update baseBranch name');
        branchState.baseBranch = baseBranch;
        delete branchState.isModified;
        branchState.pristine = false;
    }
    // if base branch sha has changed invalidate cached isBehindBase state
    if (baseBranchSha !== branchState.baseBranchSha) {
        logger_1.logger.debug('syncBranchState(): update baseBranchSha');
        delete branchState.isBehindBase;
        delete branchState.isConflicted;
        // update cached branchSha
        branchState.baseBranchSha = baseBranchSha;
        branchState.pristine = false;
    }
    // if branch sha has changed invalidate all cached states
    if (branchSha !== branchState.sha) {
        logger_1.logger.debug('syncBranchState(): update branchSha');
        delete branchState.isBehindBase;
        delete branchState.isConflicted;
        delete branchState.isModified;
        delete branchState.commitFingerprint;
        // update cached branchSha
        branchState.sha = branchSha;
        branchState.pristine = false;
    }
    return branchState;
}
async function writeUpdates(config, allBranches) {
    const branches = allBranches;
    logger_1.logger.debug(`Processing ${branches.length} branch${branches.length === 1 ? '' : 'es'}: ${branches
        .map((b) => b.branchName)
        .sort()
        .join(', ')}`);
    const prsRemaining = await (0, limits_2.getPrsRemaining)(config, branches);
    logger_1.logger.debug(`Calculated maximum PRs remaining this run: ${prsRemaining}`);
    (0, limits_1.setMaxLimit)('PullRequests', prsRemaining);
    const branchesRemaining = await (0, limits_2.getBranchesRemaining)(config, branches);
    logger_1.logger.debug(`Calculated maximum branches remaining this run: ${branchesRemaining}`);
    (0, limits_1.setMaxLimit)('Branches', branchesRemaining);
    for (const branch of branches) {
        const { baseBranch, branchName } = branch;
        const meta = { branch: branchName };
        if (config.baseBranches?.length && baseBranch) {
            meta['baseBranch'] = baseBranch;
        }
        (0, logger_1.addMeta)(meta);
        const branchExisted = await scm_1.scm.branchExists(branchName);
        const branchState = await syncBranchState(branchName, baseBranch);
        const managers = [
            ...new Set(branch.upgrades
                .map((upgrade) => manager_1.hashMap.get(upgrade.manager) ?? upgrade.manager)
                .filter(is_1.default.string)),
        ].sort();
        const commitFingerprint = (0, fingerprint_1.fingerprint)({
            commitFingerprintConfig: generateCommitFingerprintConfig(branch),
            managers,
        });
        branch.skipBranchUpdate = canSkipBranchUpdateCheck(branchState, commitFingerprint);
        const res = await (0, branch_1.processBranch)(branch);
        branch.prBlockedBy = res?.prBlockedBy;
        branch.prNo = res?.prNo;
        branch.result = res?.result;
        branch.commitFingerprint = res?.updatesVerified
            ? commitFingerprint
            : branchState.commitFingerprint;
        if (res?.commitSha) {
            (0, set_branch_commit_1.setBranchNewCommit)(branchName, baseBranch, res.commitSha);
        }
        if (branch.result === 'automerged' &&
            branch.automergeType !== 'pr-comment') {
            // Stop processing other branches because base branch has been changed
            return 'automerged';
        }
        if (!branchExisted && (await scm_1.scm.branchExists(branch.branchName))) {
            (0, limits_1.incLimitedValue)('Branches');
        }
    }
    (0, logger_1.removeMeta)(['branch', 'baseBranch']);
    return 'done';
}
//# sourceMappingURL=write.js.map