import { git, resolveProjectPath, resolveBaseBranch } from './git-helpers.js';
export async function handleBreakingCheck(projectId, config) {
    const projectPath = await resolveProjectPath(projectId);
    const baseBranch = await resolveBaseBranch(projectPath, config?.baseBranch);
    if (!baseBranch) {
        return {
            content: [
                {
                    type: 'text',
                    text: JSON.stringify({ error: 'No base branch found for comparison' }, null, 2),
                },
            ],
            isError: true,
        };
    }
    // Get changed files between current branch and base
    const changedFiles = await getChangedFiles(projectPath, baseBranch);
    // Get the full diff for analysis
    let diffContent = '';
    try {
        const contractFiles = changedFiles.filter((f) => isContractFile(f));
        if (contractFiles.length > 0) {
            const { stdout } = await git(projectPath, [
                'diff',
                `${baseBranch}...HEAD`,
                '--',
                ...contractFiles,
            ]);
            diffContent = stdout;
        }
    }
    catch {
        diffContent = '';
    }
    const changes = analyzeBreakingChanges(changedFiles, diffContent);
    // Find internal consumers of broken contracts
    const changesWithConsumers = await enrichWithConsumers(projectPath, changes);
    const hasBreakingChanges = changesWithConsumers.some((c) => c.type === 'breaking');
    const summary = buildSummary(changesWithConsumers, hasBreakingChanges);
    const result = {
        action: 'breaking-check',
        hasBreakingChanges,
        changes: changesWithConsumers,
        summary,
        message: hasBreakingChanges
            ? `BREAKING: ${changesWithConsumers.filter((c) => c.type === 'breaking').length} breaking change(s) detected`
            : `No breaking changes detected (${changesWithConsumers.length} change(s) analyzed)`,
    };
    return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
}
async function getChangedFiles(projectPath, baseBranch) {
    try {
        const { stdout } = await git(projectPath, ['diff', '--name-only', `${baseBranch}...HEAD`]);
        return stdout.trim().split('\n').filter(Boolean);
    }
    catch {
        return [];
    }
}
function isContractFile(file) {
    return (file.endsWith('.ts') ||
        file.endsWith('.graphql') ||
        file.endsWith('.yaml') ||
        file.endsWith('.yml') ||
        file.endsWith('.json') ||
        file.includes('schema') ||
        file.includes('api') ||
        file.includes('route') ||
        file.includes('endpoint'));
}
function analyzeBreakingChanges(files, diffContent) {
    const changes = [];
    for (const file of files) {
        if (!isContractFile(file)) {
            continue;
        }
        // Detect removed exports/functions (lines starting with -)
        const removedLines = diffContent
            .split('\n')
            .filter((line) => line.startsWith('-') &&
            !line.startsWith('---') &&
            (line.includes('export ') ||
                line.includes('function ') ||
                line.includes('interface ') ||
                line.includes('type ') ||
                line.includes('DELETE') ||
                line.includes('Router.delete') ||
                line.includes('app.delete')));
        for (const removed of removedLines.slice(0, 5)) {
            const changeType = classifyChange(removed, file);
            changes.push({
                type: changeType,
                description: `Removed: ${removed.slice(1).trim().slice(0, 100)}`,
                file,
                migrationPlan: changeType === 'breaking'
                    ? 'Update all consumers. Consider deprecation period of 2+ releases.'
                    : undefined,
            });
        }
        // Detect schema changes
        if (file.includes('schema') || file.includes('.graphql')) {
            const removedFields = diffContent
                .split('\n')
                .filter((line) => line.startsWith('-') && !line.startsWith('---') && /^\s*-\s+\w+/.test(line));
            for (const field of removedFields.slice(0, 3)) {
                changes.push({
                    type: 'breaking',
                    description: `Removed field: ${field.slice(1).trim()}`,
                    file,
                    migrationPlan: 'Requires schema migration. Check for data dependencies.',
                });
            }
        }
    }
    return changes;
}
function classifyChange(line, _file) {
    if (line.includes('export ') ||
        line.includes('DELETE') ||
        line.includes('Router.delete') ||
        line.includes('interface ')) {
        return 'breaking';
    }
    if (line.includes('@deprecated') || line.includes('deprecated')) {
        return 'deprecation';
    }
    return 'non-breaking';
}
async function enrichWithConsumers(projectPath, changes) {
    const enriched = [];
    for (const change of changes) {
        if (change.type !== 'breaking' || !change.file) {
            enriched.push(change);
            continue;
        }
        // Search for consumers of the changed file
        let consumers = [];
        try {
            /* v8 ignore start */
            const fileName = change.file
                .split('/')
                .pop()
                ?.replace(/\.(ts|js)$/, '') ?? '';
            /* v8 ignore end */
            if (fileName) {
                const { stdout } = await git(projectPath, ['grep', '-l', fileName, '--', '*.ts', '*.js']);
                consumers = stdout
                    .trim()
                    .split('\n')
                    .filter(Boolean)
                    .filter((f) => f !== change.file)
                    .slice(0, 5);
            }
        }
        catch {
            // ignore
        }
        enriched.push({ ...change, consumers });
    }
    return enriched;
}
function buildSummary(changes, hasBreaking) {
    const breaking = changes.filter((c) => c.type === 'breaking').length;
    const deprecations = changes.filter((c) => c.type === 'deprecation').length;
    const nonBreaking = changes.filter((c) => c.type === 'non-breaking').length;
    if (!hasBreaking && changes.length === 0) {
        return 'No contract-affecting changes detected.';
    }
    const parts = [];
    if (breaking > 0) {
        parts.push(`${breaking} breaking change(s) — requires major version bump`);
    }
    if (deprecations > 0) {
        parts.push(`${deprecations} deprecation(s) — min 2 releases before removal`);
    }
    if (nonBreaking > 0) {
        parts.push(`${nonBreaking} non-breaking change(s)`);
    }
    return parts.join('; ');
}
//# sourceMappingURL=breaking-ops.js.map