"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.writeLockUpdates = exports.isPinnedVersion = exports.extractLocks = exports.readLockFile = exports.findLockFile = void 0;
const fs_1 = require("../../../../util/fs");
const regex_1 = require("../../../../util/regex");
const versioning_1 = require("../../../versioning");
const providerStartLineRegex = (0, regex_1.regEx)(`^provider "(?<registryUrl>[^/]*)/(?<namespace>[^/]*)/(?<depName>[^/]*)"`);
const versionLineRegex = (0, regex_1.regEx)(`^(?<prefix>[\\s]*version[\\s]*=[\\s]*")(?<version>[^"']+)(?<suffix>".*)$`);
const constraintLineRegex = (0, regex_1.regEx)(`^(?<prefix>[\\s]*constraints[\\s]*=[\\s]*")(?<constraint>[^"']+)(?<suffix>".*)$`);
const hashLineRegex = (0, regex_1.regEx)(`^(?<prefix>\\s*")(?<hash>[^"]+)(?<suffix>",.*)$`);
const lockFile = '.terraform.lock.hcl';
function findLockFile(packageFilePath) {
    return (0, fs_1.findLocalSiblingOrParent)(packageFilePath, lockFile);
}
exports.findLockFile = findLockFile;
function readLockFile(lockFilePath) {
    return (0, fs_1.readLocalFile)(lockFilePath, 'utf8');
}
exports.readLockFile = readLockFile;
function extractLocks(lockFileContent) {
    const lines = lockFileContent.split(regex_1.newlineRegex);
    const blockStarts = [];
    // get first lines of blocks
    lines.forEach((line, index) => {
        if (line.startsWith('provider "')) {
            blockStarts.push(index);
        }
    });
    // sort ascending
    const sortedStarts = blockStarts.sort((a, b) => a - b);
    const contentSlices = sortedStarts.map((start, index, array) => {
        let end;
        if (index < array.length - 1) {
            end = array[index + 1];
        }
        else {
            end = lines.length - 1;
        }
        const slice = {
            lines: lines.slice(start, end),
            block: {
                start,
                end,
            },
        };
        return slice;
    });
    // generate Lock objects from slices
    const locks = contentSlices.map((slice) => {
        let packageName = '';
        let registryUrl = '';
        let version = '';
        let constraints = '';
        const relativeLineNumbers = {
            block: slice.block,
            hashes: {
                start: -1,
                end: -1,
            },
        };
        const hashes = [];
        slice.lines.forEach((line, index) => {
            const hashLineResult = hashLineRegex.exec(line);
            if (hashLineResult?.groups) {
                hashes.push(hashLineResult.groups.hash);
                relativeLineNumbers.hashes.start =
                    relativeLineNumbers.hashes.start === -1
                        ? index
                        : relativeLineNumbers.hashes.start;
                relativeLineNumbers.hashes.end = index;
                return;
            }
            const providerStartLineResult = providerStartLineRegex.exec(line);
            if (providerStartLineResult?.groups) {
                packageName = `${providerStartLineResult.groups.namespace}/${providerStartLineResult.groups.depName}`;
                registryUrl = providerStartLineResult.groups.registryUrl;
                return;
            }
            const versionLineResult = versionLineRegex.exec(line);
            if (versionLineResult?.groups) {
                version = versionLineResult.groups.version;
                relativeLineNumbers.version = index;
                return;
            }
            const constraintLineResult = constraintLineRegex.exec(line);
            if (constraintLineResult?.groups) {
                constraints = constraintLineResult.groups.constraint;
                relativeLineNumbers.constraint = index;
            }
        });
        const lock = {
            packageName,
            registryUrl: `https://${registryUrl}`,
            version,
            constraints,
            hashes,
            lineNumbers: relativeLineNumbers,
        };
        return lock;
    });
    if (locks.length === 0) {
        return null;
    }
    return locks;
}
exports.extractLocks = extractLocks;
function isPinnedVersion(value) {
    const versioning = (0, versioning_1.get)('hashicorp');
    return !!value && !!versioning.isSingleVersion(value);
}
exports.isPinnedVersion = isPinnedVersion;
function writeLockUpdates(updates, lockFilePath, oldLockFileContent) {
    const lines = oldLockFileContent.split(regex_1.newlineRegex);
    const sections = [];
    // sort updates in order of appearance in the lockfile
    // TODO #22198
    updates.sort((a, b) => a.lineNumbers.block.start - b.lineNumbers.block.start);
    updates.forEach((update, index, array) => {
        // re add leading whitespace
        let startWhitespace;
        if (index > 0) {
            // get end of the
            // TODO #22198
            startWhitespace = array[index - 1].lineNumbers.block.end;
        }
        const leadingNonRelevantLines = lines.slice(startWhitespace, 
        // TODO #22198
        update.lineNumbers.block.start);
        sections.push(leadingNonRelevantLines);
        const providerBlockLines = lines.slice(
        // TODO #22198
        update.lineNumbers.block.start, update.lineNumbers.block.end);
        const newProviderBlockLines = [];
        let hashLinePrefix = '';
        let hashLineSuffix = '';
        providerBlockLines.forEach((providerBlockLine, providerBlockIndex) => {
            const versionLine = providerBlockLine.replace(versionLineRegex, `$<prefix>${update.newVersion}$<suffix>`);
            if (versionLine !== providerBlockLine) {
                newProviderBlockLines.push(versionLine);
                return;
            }
            const constraintLine = providerBlockLine.replace(constraintLineRegex, `$<prefix>${update.newConstraint}$<suffix>`);
            if (constraintLine !== providerBlockLine) {
                newProviderBlockLines.push(constraintLine);
                return;
            }
            const hashLineRegexResult = hashLineRegex.exec(providerBlockLine);
            if (hashLineRegexResult?.groups) {
                // skip hash line but safe the whitespace
                hashLinePrefix = hashLineRegexResult.groups.prefix;
                hashLineSuffix = hashLineRegexResult.groups.suffix;
                return;
            }
            newProviderBlockLines.push(providerBlockLine);
        });
        const hashesWithWhitespace = update.newHashes.map((value) => `${hashLinePrefix}${value}${hashLineSuffix}`);
        newProviderBlockLines.splice(
        // TODO #22198
        update.lineNumbers.hashes.start, 0, ...hashesWithWhitespace);
        sections.push(newProviderBlockLines);
    });
    const trailingNotUpdatedLines = lines.slice(updates[updates.length - 1].lineNumbers.block?.end);
    sections.push(trailingNotUpdatedLines);
    const newLines = sections.reduce((previousValue, currentValue) => previousValue.concat(currentValue));
    const newContent = newLines.join('\n');
    return {
        file: {
            type: 'addition',
            path: lockFilePath,
            contents: newContent,
        },
    };
}
exports.writeLockUpdates = writeLockUpdates;
//# sourceMappingURL=util.js.map