"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.handleBeginOfFilePatch = handleBeginOfFilePatch;
exports.handleEndOfFilePatch = handleEndOfFilePatch;
exports.handleStandardPatch = handleStandardPatch;
const tokens_1 = require("./tokens");
const parsing_constants_1 = require("../../src/llm-orchestration/parser/parsing.constants");
const updateLastError = (currentError, newError) => {
    if (!currentError)
        return newError;
    const currentIsAmbiguous = currentError.message.includes('Ambiguous');
    const newIsAmbiguous = newError.message.includes('Ambiguous');
    if (currentIsAmbiguous && !newIsAmbiguous) {
        return currentError;
    }
    return newError;
};
function _findBeginOfFilePatchLocation(sourceTokens, patchTokens) {
    let replaceStart = null;
    let replaceEnd = null;
    let lastError = '';
    for (let anchorSize = 1; anchorSize <= patchTokens.length; anchorSize++) {
        const suffixAnchor = patchTokens.slice(patchTokens.length - anchorSize);
        const indices = (0, tokens_1.findAllSequences)(sourceTokens, suffixAnchor);
        if (indices.length === 1) {
            replaceStart = 0;
            const suffixIndex = indices[0];
            replaceEnd = sourceTokens[suffixIndex + anchorSize - 1].endIndex;
            break;
        }
        if (indices.length > 1) {
            const formattedAnchor = (0, tokens_1.formatAnchor)(suffixAnchor);
            const locations = indices
                .map((i) => `line ${sourceTokens[i].startPosition?.row ? sourceTokens[i].startPosition.row + 1 : '?'}`)
                .join(', ');
            lastError = `Ambiguous suffix anchor. The sequence "${formattedAnchor}" was found at ${indices.length} locations: ${locations}.`;
        }
    }
    if (replaceStart === null || replaceEnd === null) {
        const smallestAnchor = patchTokens.slice(patchTokens.length - 1);
        throw new Error(lastError ||
            `Suffix anchor not found. The sequence "${(0, tokens_1.formatAnchor)(smallestAnchor)}" could not be located.`);
    }
    return { replaceStart, replaceEnd };
}
function handleBeginOfFilePatch(sourceTokens, originalPatchTokens) {
    if (originalPatchTokens.length === 0) {
        throw new Error(`Patch is empty after removing ${parsing_constants_1.SPECIAL_PATCH_BEGIN_FILE_MARKER} marker.`);
    }
    let patchAttempt = [...originalPatchTokens];
    let lastError = null;
    while (patchAttempt.length >= 1) {
        try {
            const { replaceStart, replaceEnd } = _findBeginOfFilePatchLocation(sourceTokens, patchAttempt);
            const patchInsertStart = patchAttempt[0].startIndex;
            const patchInsertEnd = patchAttempt[patchAttempt.length - 1].endIndex;
            return { replaceStart, replaceEnd, patchInsertStart, patchInsertEnd };
        }
        catch (e) {
            lastError = updateLastError(lastError, e);
            patchAttempt = patchAttempt.slice(1);
        }
    }
    throw new Error(`Failed to apply ${parsing_constants_1.SPECIAL_PATCH_BEGIN_FILE_MARKER} patch. Could not find a unique anchor, even after trimming tokens. Last known error: ${lastError?.message}`);
}
function _findEndOfFilePatchLocation(sourceTokens, patchTokens, sourceCode) {
    let replaceStart = null;
    let replaceEnd = null;
    let lastError = '';
    for (let anchorSize = 1; anchorSize <= patchTokens.length; anchorSize++) {
        const prefixAnchor = patchTokens.slice(0, anchorSize);
        const indices = (0, tokens_1.findAllSequences)(sourceTokens, prefixAnchor);
        if (indices.length === 1) {
            replaceStart = sourceTokens[indices[0]].startIndex;
            replaceEnd = sourceCode.length;
            break;
        }
        if (indices.length > 1) {
            const formattedAnchor = (0, tokens_1.formatAnchor)(prefixAnchor);
            const locations = indices
                .map((i) => `line ${sourceTokens[i].startPosition?.row ? sourceTokens[i].startPosition.row + 1 : '?'}`)
                .join(', ');
            lastError = `Ambiguous prefix anchor. The sequence "${formattedAnchor}" was found at ${indices.length} locations: ${locations}.`;
        }
    }
    if (replaceStart === null || replaceEnd === null) {
        const smallestAnchor = patchTokens.slice(0, 1);
        throw new Error(lastError ||
            `Prefix anchor not found. The sequence "${(0, tokens_1.formatAnchor)(smallestAnchor)}" could not be located.`);
    }
    return { replaceStart, replaceEnd };
}
function handleEndOfFilePatch(sourceTokens, originalPatchTokens, sourceCode) {
    if (originalPatchTokens.length === 0) {
        throw new Error(`Patch is empty after removing ${parsing_constants_1.SPECIAL_PATCH_END_FILE_MARKER} marker.`);
    }
    let patchAttempt = [...originalPatchTokens];
    let lastError = null;
    while (patchAttempt.length >= 1) {
        try {
            const { replaceStart, replaceEnd } = _findEndOfFilePatchLocation(sourceTokens, patchAttempt, sourceCode);
            const patchInsertStart = patchAttempt[0].startIndex;
            const patchInsertEnd = patchAttempt[patchAttempt.length - 1].endIndex;
            return { replaceStart, replaceEnd, patchInsertStart, patchInsertEnd };
        }
        catch (e) {
            lastError = updateLastError(lastError, e);
            patchAttempt = patchAttempt.slice(0, -1);
        }
    }
    throw new Error(`Failed to apply ${parsing_constants_1.SPECIAL_PATCH_END_FILE_MARKER} patch. Could not find a unique anchor, even after trimming tokens. Last known error: ${lastError?.message}`);
}
function _findPrefixLocation(sourceTokens, patchTokens) {
    let prefixAnchor = null;
    let prefixIndex = null;
    let bestPrefixError = null;
    for (let prefixSize = 1; prefixSize < patchTokens.length; prefixSize++) {
        const currentPrefix = patchTokens.slice(0, prefixSize);
        const prefixIndices = (0, tokens_1.findAllSequences)(sourceTokens, currentPrefix);
        if (prefixIndices.length === 1) {
            prefixAnchor = currentPrefix;
            prefixIndex = prefixIndices[0];
            bestPrefixError = null;
            break;
        }
        if (prefixIndices.length > 1) {
            const formatted = (0, tokens_1.formatAnchor)(currentPrefix);
            const locations = prefixIndices
                .map((i) => `line ${sourceTokens[i].startPosition?.row ? sourceTokens[i].startPosition.row + 1 : '?'}`)
                .join(', ');
            bestPrefixError = `Ambiguous prefix anchor. The sequence "${formatted}" was found at ${prefixIndices.length} locations: ${locations}.`;
        }
        if (prefixIndices.length === 0) {
            if (!bestPrefixError) {
                const formatted = (0, tokens_1.formatAnchor)(currentPrefix);
                bestPrefixError = `Prefix anchor not found: "${formatted}"`;
            }
            break;
        }
    }
    if (!prefixAnchor || prefixIndex === null) {
        throw new Error(bestPrefixError || 'Could not find a unique prefix anchor.');
    }
    const replaceStart = sourceTokens[prefixIndex].startIndex;
    return { prefixAnchor, prefixIndex, replaceStart };
}
function _findSuffixLocation(sourceTokens, patchTokens, prefixAnchor, prefixIndex) {
    let suffixAnchor = null;
    let suffixIndex = null;
    let bestSuffixError = null;
    const searchStartIndex = prefixIndex + prefixAnchor.length;
    const sourceAfterPrefix = sourceTokens.slice(searchStartIndex);
    for (let suffixSize = 1; suffixSize <= patchTokens.length - prefixAnchor.length; suffixSize++) {
        const currentSuffix = patchTokens.slice(patchTokens.length - suffixSize);
        const suffixIndices = (0, tokens_1.findAllSequences)(sourceAfterPrefix, currentSuffix);
        if (suffixIndices.length === 1) {
            suffixAnchor = currentSuffix;
            suffixIndex = searchStartIndex + suffixIndices[0];
            bestSuffixError = null;
            break;
        }
        if (suffixIndices.length > 1) {
            const formatted = (0, tokens_1.formatAnchor)(currentSuffix);
            const locations = suffixIndices
                .map((i) => `line ${sourceTokens[searchStartIndex + i].startPosition?.row
                ? sourceTokens[searchStartIndex + i].startPosition.row + 1
                : '?'}`)
                .join(', ');
            bestSuffixError = `Ambiguous suffix anchor. The sequence "${formatted}" was found ${suffixIndices.length} times after the prefix: ${locations}.`;
        }
    }
    if (!suffixAnchor || suffixIndex === null) {
        if (bestSuffixError) {
            throw new Error(bestSuffixError);
        }
        const prefixLocation = `line ${sourceTokens[prefixIndex].startPosition?.row
            ? sourceTokens[prefixIndex].startPosition.row + 1
            : '?'}`;
        const formattedPrefix = (0, tokens_1.formatAnchor)(prefixAnchor);
        const smallestSuffix = (0, tokens_1.formatAnchor)(patchTokens.slice(patchTokens.length - 1));
        throw new Error(`Could not find a unique suffix anchor after the prefix anchor "${formattedPrefix}" (found at ${prefixLocation}). ` +
            `The smallest suffix searched for ("${smallestSuffix}") was not found after it.`);
    }
    const replaceEnd = sourceTokens[suffixIndex + suffixAnchor.length - 1].endIndex;
    return { replaceEnd };
}
function handleStandardPatch(sourceTokens, originalPatchTokens) {
    if (originalPatchTokens.length < 2) {
        throw new Error('Patch must contain at least two tokens to form a prefix and a suffix.');
    }
    let startTrim = 0;
    const endTrim = 0;
    let lastError = null;
    let prefixInfo = null;
    let patchAttempt = [...originalPatchTokens];
    while (patchAttempt.length >= 2) {
        try {
            prefixInfo = _findPrefixLocation(sourceTokens, patchAttempt);
            startTrim = originalPatchTokens.length - patchAttempt.length;
            break;
        }
        catch (e) {
            lastError = updateLastError(lastError, e);
            patchAttempt = patchAttempt.slice(1);
        }
    }
    if (!prefixInfo) {
        throw new Error(`Failed to apply patch. Could not find a unique prefix anchor, even after trimming tokens. Last known error: ${lastError?.message}`);
    }
    patchAttempt = originalPatchTokens.slice(startTrim);
    lastError = null;
    while (patchAttempt.length >= prefixInfo.prefixAnchor.length + 1) {
        try {
            const { replaceEnd } = _findSuffixLocation(sourceTokens, patchAttempt, prefixInfo.prefixAnchor, prefixInfo.prefixIndex);
            const patchInsertStart = patchAttempt[0].startIndex;
            const patchInsertEnd = patchAttempt[patchAttempt.length - 1].endIndex;
            return {
                replaceStart: prefixInfo.replaceStart,
                replaceEnd,
                patchInsertStart,
                patchInsertEnd,
            };
        }
        catch (e) {
            lastError = updateLastError(lastError, e);
            patchAttempt = patchAttempt.slice(0, -1);
        }
    }
    throw new Error(`Failed to apply patch. Could not find a unique suffix anchor, even after trimming tokens. Last known error: ${lastError?.message}`);
}
//# sourceMappingURL=patcher.js.map