// Planu — Duplication finder (SPEC-482)
// Hash-compares normalized code blocks with a sliding window to detect copy-paste.
import { readFileSync } from 'node:fs';
import { createHash } from 'node:crypto';
/** Minimum number of lines for a block to be considered a duplication candidate. */
const MIN_BLOCK_LINES = 6;
/** Normalize a source line by stripping leading/trailing whitespace and comments. */
function normalizeLine(line) {
    return line.replace(/\/\/.*$/, '').trim();
}
/** Compute a SHA-1 hash for a normalized block of lines. */
function hashBlock(lines) {
    return createHash('sha1').update(lines.join('\n')).digest('hex');
}
/** Collect all sliding-window blocks from a file. */
function extractBlocks(filePath, blockSize) {
    let source;
    try {
        source = readFileSync(filePath, 'utf8');
    }
    catch {
        return [];
    }
    const rawLines = source.split('\n');
    const normalizedLines = rawLines.map(normalizeLine);
    const blocks = [];
    for (let i = 0; i <= normalizedLines.length - blockSize; i++) {
        const window = normalizedLines.slice(i, i + blockSize);
        // Skip windows that are mostly blank
        const nonEmpty = window.filter((l) => l.length > 0);
        if (nonEmpty.length < Math.ceil(blockSize * 0.6)) {
            continue;
        }
        blocks.push({
            file: filePath,
            startLine: i + 1,
            hash: hashBlock(window),
            snippet: rawLines.slice(i, i + Math.min(3, blockSize)).join('\n'),
        });
    }
    return blocks;
}
/** Find duplicated code blocks across the given files. */
export function findDuplications(filePaths, blockSize = MIN_BLOCK_LINES) {
    const seen = new Map();
    const reported = new Set();
    const candidates = [];
    for (const fp of filePaths) {
        const blocks = extractBlocks(fp, blockSize);
        for (const block of blocks) {
            const existing = seen.get(block.hash);
            if (existing !== undefined && existing.file !== block.file) {
                const key = `${block.hash}:${block.file}`;
                if (!reported.has(key)) {
                    reported.add(key);
                    candidates.push({
                        file: block.file,
                        line: block.startLine,
                        category: 'duplication',
                        severity: 'medium',
                        description: `${blockSize}-line block duplicated from ${existing.file}:${existing.startLine}.`,
                        suggestion: 'Extract the shared logic into a reusable function or utility.',
                        snippet: block.snippet,
                    });
                }
            }
            else if (existing === undefined) {
                seen.set(block.hash, block);
            }
        }
    }
    return candidates;
}
//# sourceMappingURL=duplication-finder.js.map