"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.writeUpdates = exports.syncBranchState = exports.canSkipBranchUpdateCheck = void 0;
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 repository_1 = require("../../../util/cache/repository");
const fingerprint_1 = require("../../../util/fingerprint");
const git_1 = require("../../../util/git");
const set_branch_commit_1 = require("../../../util/git/set-branch-commit");
const limits_1 = require("../../global/limits");
const types_1 = require("../../types");
const branch_1 = require("../update/branch");
const limits_2 = require("./limits");
function canSkipBranchUpdateCheck(branchState, branchFingerprint) {
    if (!branchState.branchFingerprint) {
        logger_1.logger.trace('branch.isUpToDate(): no fingerprint');
        return false;
    }
    if (branchFingerprint !== branchState.branchFingerprint) {
        logger_1.logger.debug('branch.isUpToDate(): needs recalculation');
        return false;
    }
    logger_1.logger.debug('branch.isUpToDate(): using cached result "true"');
    return true;
}
exports.canSkipBranchUpdateCheck = canSkipBranchUpdateCheck;
function syncBranchState(branchName, baseBranch) {
    logger_1.logger.debug('syncBranchState()');
    const branchSha = (0, git_1.getBranchCommit)(branchName);
    const baseBranchSha = (0, git_1.getBranchCommit)(baseBranch);
    const cache = (0, repository_1.getCache)();
    cache.branches ?? (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;
    }
    // if base branch sha has changed invalidate cached isBehindBase state
    if (baseBranchSha !== branchState.baseBranchSha) {
        logger_1.logger.debug('syncBranchState(): update baseBranchSha');
        delete branchState.isBehindBase;
        // update cached branchSha
        branchState.baseBranchSha = baseBranchSha;
    }
    // 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.isModified;
        delete branchState.branchFingerprint;
        // update cached branchSha
        branchState.sha = branchSha;
    }
    return branchState;
}
exports.syncBranchState = syncBranchState;
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({ prsRemaining }, 'Calculated maximum PRs remaining this run');
    (0, limits_1.setMaxLimit)(limits_1.Limit.PullRequests, prsRemaining);
    const branchesRemaining = await (0, limits_2.getBranchesRemaining)(config, branches);
    logger_1.logger.debug({ branchesRemaining }, 'Calculated maximum branches remaining this run');
    (0, limits_1.setMaxLimit)(limits_1.Limit.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 = (0, git_1.branchExists)(branchName);
        // TODO: base branch name cannot be undefined - fix optional types (#7154)
        const branchState = 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 branchFingerprint = (0, fingerprint_1.fingerprint)({
            branch,
            managers,
        });
        branch.skipBranchUpdate = canSkipBranchUpdateCheck(branchState, branchFingerprint);
        const res = await (0, branch_1.processBranch)(branch);
        branch.prBlockedBy = res?.prBlockedBy;
        branch.prNo = res?.prNo;
        branch.result = res?.result;
        branch.branchFingerprint =
            res?.commitSha || !branchState.branchFingerprint
                ? branchFingerprint
                : branchState.branchFingerprint;
        if (res?.commitSha) {
            // TODO: base branch name cannot be undefined - fix optional types (#7154)
            (0, set_branch_commit_1.setBranchNewCommit)(branchName, baseBranch, res.commitSha);
        }
        if (branch.result === types_1.BranchResult.Automerged &&
            branch.automergeType !== 'pr-comment') {
            // Stop processing other branches because base branch has been changed
            return 'automerged';
        }
        if (!branchExisted && (0, git_1.branchExists)(branch.branchName)) {
            (0, limits_1.incLimitedValue)(limits_1.Limit.Branches);
        }
    }
    (0, logger_1.removeMeta)(['branch', 'baseBranch']);
    return 'done';
}
exports.writeUpdates = writeUpdates;
//# sourceMappingURL=write.js.map