// tools/github-review-handler.ts — Handler for review_pr tool.
import { createPlatformClient, getRemoteUrl } from '../engine/github/client.js';
import { analyzeDiff, parseDiffStats, generateSummaryFinding, } from '../engine/github/review-analyzer.js';
import { runAllDimensions, runQualityDimensions } from '../engine/github/review-dimensions.js';
import { mergeFindings } from '../engine/github/findings-merger.js';
import { execFile as nodeExecFile } from 'node:child_process';
import { promisify } from 'node:util';
/* v8 ignore next 3 -- default exec, always overridden in tests */
const defaultExec = async (cmd, args) => {
    return promisify(nodeExecFile)(cmd, args, { maxBuffer: 10 * 1024 * 1024 });
};
// Extract SPEC-XXX from a branch name like feat/SPEC-303-expert-pr-review
function extractSpecId(branchName) {
    const match = /SPEC-(\d+)/i.exec(branchName);
    return match ? `SPEC-${match[1]}` : undefined;
}
function formatFinding(f) {
    const location = f.line ? `${f.file}:${String(f.line)}` : f.file;
    const lines = [`**[${f.category.toUpperCase()}]** ${location}`];
    lines.push(`  ${f.message}`);
    if (f.suggestion) {
        lines.push(`  Suggestion: ${f.suggestion}`);
    }
    lines.push('');
    return lines;
}
async function handleExpertReview(prNumber, diff, exec) {
    // Try to get current branch name for spec-drift detection
    let specId;
    try {
        const { stdout } = await exec('git', ['rev-parse', '--abbrev-ref', 'HEAD']);
        specId = extractSpecId(stdout.trim());
    }
    catch {
        // ignore — spec-drift dimension will be skipped
    }
    const context = { hasClaudeMd: true, specId };
    const dimensionResults = await runAllDimensions(diff, context);
    const merged = mergeFindings(dimensionResults);
    const stats = parseDiffStats(diff);
    const sections = [];
    sections.push(`## Expert Review of PR #${String(prNumber)}\n`);
    sections.push(`**Files changed:** ${String(stats.filesChanged)}`);
    sections.push(`**Lines:** +${String(stats.additions)} -${String(stats.deletions)}`);
    sections.push(`**Dimensions:** ${merged.dimensions.join(', ')}` +
        ` | **Total findings:** ${String(merged.totalFindings)}\n`);
    if (merged.critical.length > 0) {
        sections.push('### Critical\n');
        for (const f of merged.critical) {
            sections.push(...formatFinding(f));
        }
    }
    if (merged.suggestions.length > 0) {
        sections.push('### Suggestions\n');
        for (const f of merged.suggestions) {
            sections.push(...formatFinding(f));
        }
    }
    if (merged.nits.length > 0) {
        sections.push('### Nits\n');
        for (const f of merged.nits) {
            sections.push(...formatFinding(f));
        }
    }
    if (merged.totalFindings === 0) {
        sections.push('\nNo issues found across all review dimensions.');
    }
    return {
        content: [{ type: 'text', text: sections.join('\n') }],
        _meta: {
            prNumber,
            reviewType: 'expert',
            filesChanged: stats.filesChanged,
            additions: stats.additions,
            deletions: stats.deletions,
            findingsCount: merged.totalFindings,
            critical: merged.critical.length,
            suggestions: merged.suggestions.length,
            nits: merged.nits.length,
        },
    };
}
async function handleQualityReview(prNumber, diff) {
    const dimensionResults = await runQualityDimensions(diff);
    const merged = mergeFindings(dimensionResults);
    const stats = parseDiffStats(diff);
    const sections = [];
    sections.push(`## Quality Review of PR #${String(prNumber)}\n`);
    sections.push(`**Files changed:** ${String(stats.filesChanged)}`);
    sections.push(`**Lines:** +${String(stats.additions)} -${String(stats.deletions)}`);
    sections.push(`**Dimensions:** ${merged.dimensions.join(', ')}` +
        ` | **Total findings:** ${String(merged.totalFindings)}\n`);
    if (merged.critical.length > 0) {
        sections.push('### Critical\n');
        for (const f of merged.critical) {
            sections.push(...formatFinding(f));
        }
    }
    if (merged.suggestions.length > 0) {
        sections.push('### Suggestions\n');
        for (const f of merged.suggestions) {
            sections.push(...formatFinding(f));
        }
    }
    if (merged.nits.length > 0) {
        sections.push('### Nits\n');
        for (const f of merged.nits) {
            sections.push(...formatFinding(f));
        }
    }
    if (merged.totalFindings === 0) {
        sections.push('\nNo quality issues found.');
    }
    return {
        content: [{ type: 'text', text: sections.join('\n') }],
        _meta: {
            prNumber,
            reviewType: 'quality',
            filesChanged: stats.filesChanged,
            additions: stats.additions,
            deletions: stats.deletions,
            findingsCount: merged.totalFindings,
            critical: merged.critical.length,
            suggestions: merged.suggestions.length,
            nits: merged.nits.length,
        },
    };
}
export async function handleReviewPR(args, exec = defaultExec) {
    const remoteUrl = await getRemoteUrl(exec);
    const client = createPlatformClient(remoteUrl, exec);
    const diff = await client.getPRDiff(args.prNumber);
    if (args.reviewType === 'expert') {
        return handleExpertReview(args.prNumber, diff, exec);
    }
    if (args.reviewType === 'quality') {
        return handleQualityReview(args.prNumber, diff);
    }
    const stats = parseDiffStats(diff);
    const reviewType = args.reviewType;
    const findings = analyzeDiff(diff, reviewType);
    const summaryFinding = generateSummaryFinding(stats.filesChanged, stats.additions, stats.deletions);
    const allFindings = [summaryFinding, ...findings];
    const sections = [];
    sections.push(`## Review of PR #${String(args.prNumber)} (${reviewType})\n`);
    sections.push(`**Files changed:** ${String(stats.filesChanged)}`);
    sections.push(`**Lines:** +${String(stats.additions)} -${String(stats.deletions)}\n`);
    if (stats.files.length > 0) {
        sections.push('### Files\n');
        for (const f of stats.files) {
            sections.push(`- ${f}`);
        }
        sections.push('');
    }
    if (findings.length > 0) {
        sections.push('### Findings\n');
        for (const f of findings) {
            const location = f.line ? `${f.file}:${String(f.line)}` : f.file;
            sections.push(`**[${f.severity.toUpperCase()}]** ${location}`);
            sections.push(`  ${f.message}`);
            if (f.suggestion) {
                sections.push(`  Suggestion: ${f.suggestion}`);
            }
            sections.push('');
        }
    }
    else if (reviewType !== 'summary') {
        sections.push(`\nNo ${reviewType} issues found in this PR.`);
    }
    return {
        content: [
            {
                type: 'text',
                text: sections.join('\n'),
            },
        ],
        _meta: {
            prNumber: args.prNumber,
            reviewType,
            filesChanged: stats.filesChanged,
            additions: stats.additions,
            deletions: stats.deletions,
            findingsCount: allFindings.length,
        },
    };
}
//# sourceMappingURL=github-review-handler.js.map