"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContextAwareMatcher = void 0;
class ContextAwareMatcher {
    constructor() {
        this.name = 'ContextAwareMatcher';
        this.confidenceThreshold = parseFloat(process.env.CONTEXT_AWARE_MATCH_THRESHOLD || '0.85');
        this.anchorWindow = parseInt(process.env.CONTEXT_ANCHOR_WINDOW || '3');
    }
    getAdaptiveAnchorWindow(contentLines) {
        const totalLines = contentLines.length;
        const totalChars = contentLines.join('\n').length;
        if (totalLines === 0 || totalChars === 0) {
            return 3;
        }
        const density = (totalLines / totalChars) * 1000;
        if (density > 50)
            return 5;
        if (density > 25)
            return 4;
        return 3;
    }
    match(searchBlock, content) {
        const searchLines = searchBlock.split('\n');
        const contentLines = content.split('\n');
        const adaptiveWindow = this.getAdaptiveAnchorWindow(contentLines);
        const candidates = this.findCandidatesWithScoring(searchBlock, searchLines, contentLines, adaptiveWindow);
        if (candidates.length === 0) {
            return {
                found: false,
                unique: false,
                confidence: 0,
                candidates: [],
            };
        }
        const highConfidenceCandidates = candidates.filter((c) => c.confidence >= this.confidenceThreshold);
        if (highConfidenceCandidates.length === 0) {
            return {
                found: true,
                unique: false,
                confidence: Math.max(...candidates.map((c) => c.confidence)),
                candidates,
            };
        }
        if (highConfidenceCandidates.length === 1) {
            const candidate = highConfidenceCandidates[0];
            const before = this.extractBefore(candidate, contentLines);
            const after = this.extractAfter(candidate, contentLines);
            return {
                found: true,
                unique: true,
                confidence: candidate.confidence,
                before,
                after,
            };
        }
        highConfidenceCandidates.sort((a, b) => b.confidence - a.confidence);
        const best = highConfidenceCandidates[0];
        const secondBest = highConfidenceCandidates[1];
        if (best.confidence - secondBest.confidence >= 0.25) {
            const before = this.extractBefore(best, contentLines);
            const after = this.extractAfter(best, contentLines);
            return {
                found: true,
                unique: true,
                confidence: best.confidence,
                before,
                after,
            };
        }
        return {
            found: true,
            unique: false,
            confidence: Math.max(...highConfidenceCandidates.map((c) => c.confidence)),
            candidates: highConfidenceCandidates,
        };
    }
    findCandidatesWithScoring(searchBlock, searchLines, contentLines, windowSize) {
        const candidates = [];
        for (let i = 0; i <= contentLines.length - searchLines.length; i++) {
            const windowLines = contentLines.slice(i, i + searchLines.length);
            const windowBlock = windowLines.join('\n');
            const blockSimilarity = this.calculateSimilarity(searchBlock, windowBlock);
            if (blockSimilarity < 0.5) {
                continue;
            }
            const contextScore = this.calculateContextUniqueness(i, searchLines.length, contentLines, windowSize);
            let combinedConfidence;
            if (contextScore > 0.5) {
                combinedConfidence = blockSimilarity * 0.4 + contextScore * 0.6;
            }
            else {
                combinedConfidence = blockSimilarity * 0.9 + contextScore * 0.1;
            }
            const beforeAnchor = i > 0 ? contentLines[i - 1] : undefined;
            const afterAnchor = i + searchLines.length < contentLines.length
                ? contentLines[i + searchLines.length]
                : undefined;
            candidates.push({
                block: windowBlock,
                startLine: i,
                endLine: i + searchLines.length - 1,
                confidence: combinedConfidence,
                beforeAnchor,
                afterAnchor,
            });
        }
        return candidates.sort((a, b) => b.confidence - a.confidence);
    }
    calculateContextUniqueness(startIndex, blockLength, contentLines, windowSize) {
        const totalLines = contentLines.length;
        const beforeStart = Math.max(0, startIndex - windowSize);
        const beforeLines = contentLines.slice(beforeStart, startIndex);
        const afterEnd = Math.min(totalLines, startIndex + blockLength + windowSize);
        const afterLines = contentLines.slice(startIndex + blockLength, afterEnd);
        let beforeOccurrences = 0;
        if (beforeLines.length > 0) {
            for (let i = 0; i <= totalLines - beforeLines.length; i++) {
                const window = contentLines.slice(i, i + beforeLines.length);
                if (this.arraysEqual(window, beforeLines)) {
                    beforeOccurrences++;
                }
            }
        }
        else {
            beforeOccurrences = 0;
        }
        let afterOccurrences = 0;
        if (afterLines.length > 0) {
            for (let i = 0; i <= totalLines - afterLines.length; i++) {
                const window = contentLines.slice(i, i + afterLines.length);
                if (this.arraysEqual(window, afterLines)) {
                    afterOccurrences++;
                }
            }
        }
        else {
            afterOccurrences = 0;
        }
        const beforeUniqueness = beforeOccurrences === 0 ? 1.0 : 1.0 / beforeOccurrences;
        const afterUniqueness = afterOccurrences === 0 ? 1.0 : 1.0 / afterOccurrences;
        return (beforeUniqueness + afterUniqueness) / 2;
    }
    arraysEqual(a, b) {
        if (a.length !== b.length)
            return false;
        for (let i = 0; i < a.length; i++) {
            if (a[i] !== b[i])
                return false;
        }
        return true;
    }
    calculateSimilarity(a, b) {
        if (a === b)
            return 1.0;
        if (a.length === 0)
            return 0.0;
        if (b.length === 0)
            return 0.0;
        const distance = this.levenshteinDistance(a, b);
        const maxLen = Math.max(a.length, b.length);
        return 1.0 - distance / maxLen;
    }
    levenshteinDistance(a, b) {
        const matrix = [];
        for (let i = 0; i <= b.length; i++) {
            matrix[i] = [i];
        }
        for (let j = 0; j <= a.length; j++) {
            matrix[0][j] = j;
        }
        for (let i = 1; i <= b.length; i++) {
            for (let j = 1; j <= a.length; j++) {
                const cost = b[i - 1] === a[j - 1] ? 0 : 1;
                matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j - 1] + cost);
            }
        }
        return matrix[b.length][a.length];
    }
    extractBefore(candidate, contentLines) {
        return contentLines.slice(0, candidate.startLine).join('\n');
    }
    extractAfter(candidate, contentLines) {
        return contentLines.slice(candidate.endLine + 1).join('\n');
    }
}
exports.ContextAwareMatcher = ContextAwareMatcher;
//# sourceMappingURL=context-aware.matcher.js.map