"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.doAutoReplace = exports.checkBranchDepsMatchBaseDeps = exports.confirmIfDepUpdated = void 0;
const tslib_1 = require("tslib");
// TODO #22198
const is_1 = tslib_1.__importDefault(require("@sindresorhus/is"));
const error_messages_1 = require("../../../../constants/error-messages");
const logger_1 = require("../../../../logger");
const manager_1 = require("../../../../modules/manager");
const fs_1 = require("../../../../util/fs");
const regex_1 = require("../../../../util/regex");
const string_1 = require("../../../../util/string");
const template_1 = require("../../../../util/template");
async function confirmIfDepUpdated(upgrade, newContent) {
    const { manager, packageFile, depIndex } = upgrade;
    let newUpgrade;
    try {
        const newExtract = await (0, manager_1.extractPackageFile)(manager, newContent, packageFile, upgrade);
        // istanbul ignore if
        if (!newExtract) {
            // TODO: fix types (#22198)
            logger_1.logger.debug(`Could not extract ${packageFile}`);
            return false;
        }
        newUpgrade = newExtract.deps[depIndex];
    }
    catch (err) /* istanbul ignore next */ {
        logger_1.logger.debug({ manager, packageFile, err }, 'Failed to parse newContent');
    }
    if (!newUpgrade) {
        logger_1.logger.debug(`No newUpgrade in ${packageFile}`);
        return false;
    }
    if (upgrade.depName !== newUpgrade.depName &&
        upgrade.newName !== newUpgrade.depName) {
        logger_1.logger.debug({
            manager,
            packageFile,
            currentDepName: upgrade.depName,
            newDepName: newUpgrade.depName,
        }, 'depName mismatch');
        return false;
    }
    if (upgrade.newName && upgrade.newName !== newUpgrade.depName) {
        logger_1.logger.debug({
            manager,
            packageFile,
            currentDepName: upgrade.depName,
            newDepName: newUpgrade.depName,
        }, 'depName is not updated');
        return false;
    }
    if (upgrade.newValue && upgrade.newValue !== newUpgrade.currentValue) {
        logger_1.logger.debug({
            manager,
            packageFile,
            expectedValue: upgrade.newValue,
            foundValue: newUpgrade.currentValue,
        }, 'Value is not updated');
        return false;
    }
    if (upgrade.newDigest &&
        (upgrade.isPinDigest === true || upgrade.currentDigest) &&
        upgrade.newDigest !== newUpgrade.currentDigest) {
        logger_1.logger.debug({
            manager,
            packageFile,
            expectedValue: upgrade.newDigest,
            foundValue: newUpgrade.currentDigest,
        }, 'Digest is not updated');
        return false;
    }
    return true;
}
exports.confirmIfDepUpdated = confirmIfDepUpdated;
function getDepsSignature(deps) {
    // TODO: types (#22198)
    return deps
        .map((dep) => `${(dep.depName ?? dep.packageName)}${(dep.packageName ??
        dep.depName)}`)
        .join(',');
}
async function checkBranchDepsMatchBaseDeps(upgrade, branchContent) {
    const { baseDeps, manager, packageFile } = upgrade;
    try {
        const res = await (0, manager_1.extractPackageFile)(manager, branchContent, packageFile, upgrade);
        const branchDeps = res.deps;
        return getDepsSignature(baseDeps) === getDepsSignature(branchDeps);
    }
    catch (err) /* istanbul ignore next */ {
        logger_1.logger.info({ manager, packageFile }, 'Failed to parse branchContent - rebasing');
        return false;
    }
}
exports.checkBranchDepsMatchBaseDeps = checkBranchDepsMatchBaseDeps;
async function checkExistingBranch(upgrade, existingContent) {
    const { packageFile, depName } = upgrade;
    if (!(await checkBranchDepsMatchBaseDeps(upgrade, existingContent))) {
        logger_1.logger.debug({ packageFile, depName }, 'Rebasing branch after deps list has changed');
        return null;
    }
    if (!(await confirmIfDepUpdated(upgrade, existingContent))) {
        logger_1.logger.debug({ packageFile, depName }, 'Rebasing after outdated branch dep found');
        return null;
    }
    // TODO: fix types (#22198)
    logger_1.logger.debug(`Branch dep ${depName} in ${packageFile} is already updated`);
    return existingContent;
}
async function doAutoReplace(upgrade, existingContent, reuseExistingBranch, firstUpdate = true) {
    const { packageFile, depName, newName, currentValue, newValue, currentDigest, currentDigestShort, newDigest, autoReplaceGlobalMatch, autoReplaceStringTemplate, } = upgrade;
    /*
      If replacement support for more managers is added,
      please also update the list in docs/usage/configuration-options.md
      at replacementName and replacementVersion
    */
    if (reuseExistingBranch) {
        return await checkExistingBranch(upgrade, existingContent);
    }
    const replaceWithoutReplaceString = is_1.default.string(newName) &&
        newName !== depName &&
        (is_1.default.undefined(upgrade.replaceString) ||
            !upgrade.replaceString?.includes(depName));
    const replaceString = upgrade.replaceString ?? currentValue ?? currentDigest;
    logger_1.logger.trace({ depName, replaceString }, 'autoReplace replaceString');
    let searchIndex;
    if (replaceWithoutReplaceString) {
        const depIndex = existingContent.indexOf(depName);
        const valIndex = existingContent.indexOf(currentValue);
        searchIndex = depIndex < valIndex ? depIndex : valIndex;
    }
    else {
        searchIndex = existingContent.indexOf(replaceString);
    }
    if (searchIndex === -1) {
        logger_1.logger.info({ packageFile, depName, existingContent, replaceString }, 'Cannot find replaceString in current file content. Was it already updated?');
        return existingContent;
    }
    try {
        let newString;
        if (autoReplaceStringTemplate && !newName) {
            newString = (0, template_1.compile)(autoReplaceStringTemplate, upgrade, false);
        }
        else {
            newString = replaceString;
            const autoReplaceRegExpFlag = autoReplaceGlobalMatch ? 'g' : '';
            if (currentValue && newValue) {
                newString = newString.replace((0, regex_1.regEx)((0, regex_1.escapeRegExp)(currentValue), autoReplaceRegExpFlag), newValue);
            }
            if (depName && newName) {
                newString = newString.replace((0, regex_1.regEx)((0, regex_1.escapeRegExp)(depName), autoReplaceRegExpFlag), newName);
            }
            if (currentDigest && newDigest) {
                newString = newString.replace((0, regex_1.regEx)((0, regex_1.escapeRegExp)(currentDigest), autoReplaceRegExpFlag), newDigest);
            }
            else if (currentDigestShort && newDigest) {
                newString = newString.replace((0, regex_1.regEx)((0, regex_1.escapeRegExp)(currentDigestShort), autoReplaceRegExpFlag), newDigest);
            }
        }
        if (!firstUpdate && (await confirmIfDepUpdated(upgrade, existingContent))) {
            logger_1.logger.debug({ packageFile, depName }, 'Package file is already updated - no work to do');
            return existingContent;
        }
        logger_1.logger.debug({ packageFile, depName }, `Starting search at index ${searchIndex}`);
        let newContent = existingContent;
        let nameReplaced = !newName;
        let valueReplaced = !newValue;
        let startIndex = searchIndex;
        // Iterate through the rest of the file
        for (; searchIndex < newContent.length; searchIndex += 1) {
            // First check if we have a hit for the old version
            if (replaceWithoutReplaceString) {
                // look for depName and currentValue
                if (newName && (0, string_1.matchAt)(newContent, searchIndex, depName)) {
                    logger_1.logger.debug({ packageFile, depName }, `Found depName at index ${searchIndex}`);
                    if (nameReplaced) {
                        startIndex += 1;
                        searchIndex = startIndex;
                        await (0, fs_1.writeLocalFile)(upgrade.packageFile, existingContent);
                        newContent = existingContent;
                        nameReplaced = false;
                        valueReplaced = false;
                        continue;
                    }
                    // replace with newName
                    newContent = (0, string_1.replaceAt)(newContent, searchIndex, depName, newName);
                    await (0, fs_1.writeLocalFile)(upgrade.packageFile, newContent);
                    nameReplaced = true;
                }
                else if (newValue &&
                    (0, string_1.matchAt)(newContent, searchIndex, currentValue)) {
                    logger_1.logger.debug({ packageFile, currentValue }, `Found currentValue at index ${searchIndex}`);
                    // Now test if the result matches
                    newContent = (0, string_1.replaceAt)(newContent, searchIndex, currentValue, newValue);
                    await (0, fs_1.writeLocalFile)(upgrade.packageFile, newContent);
                    valueReplaced = true;
                }
                if (nameReplaced && valueReplaced) {
                    if (await confirmIfDepUpdated(upgrade, newContent)) {
                        return newContent;
                    }
                    await (0, fs_1.writeLocalFile)(upgrade.packageFile, existingContent);
                    newContent = existingContent;
                    nameReplaced = false;
                    valueReplaced = false;
                }
            }
            else if ((0, string_1.matchAt)(newContent, searchIndex, replaceString)) {
                logger_1.logger.debug({ packageFile, depName }, `Found match at index ${searchIndex}`);
                // Now test if the result matches
                newContent = (0, string_1.replaceAt)(newContent, searchIndex, replaceString, newString);
                await (0, fs_1.writeLocalFile)(upgrade.packageFile, newContent);
                if (await confirmIfDepUpdated(upgrade, newContent)) {
                    return newContent;
                }
                await (0, fs_1.writeLocalFile)(upgrade.packageFile, existingContent);
                newContent = existingContent;
            }
        }
    }
    catch (err) /* istanbul ignore next */ {
        logger_1.logger.debug({ packageFile, depName, err }, 'doAutoReplace error');
    }
    // istanbul ignore next
    throw new Error(error_messages_1.WORKER_FILE_UPDATE_FAILED);
}
exports.doAutoReplace = doAutoReplace;
//# sourceMappingURL=auto-replace.js.map