// tools/crash-shield-handler.ts — Crash Shield tool handlers (SPEC-442)
import { z } from 'zod';
import { getCrashShieldConfig, saveCrashShieldConfig } from '../storage/crash-shield-store.js';
import { scanCrashRisks, fixCrashRisks } from '../engine/crash-shield/index.js';
// ---------------------------------------------------------------------------
// Zod schemas (exported for use in register-crash-shield-tools.ts)
// ---------------------------------------------------------------------------
export const ScanCrashRisksSchema = z.object({
    projectId: z.string().describe('Project ID'),
    projectPath: z.string().optional().describe('Absolute path to the project root'),
});
export const FixCrashRisksSchema = z.object({
    projectId: z.string().describe('Project ID'),
    projectPath: z.string().optional().describe('Absolute path to the project root'),
    dryRun: z
        .boolean()
        .optional()
        .describe('If true (default), show what would change without applying fixes'),
});
export const ConfigureCrashRulesSchema = z.object({
    projectId: z.string().describe('Project ID'),
    enabledLanguages: z
        .array(z.string())
        .optional()
        .describe('Languages to scan (e.g. ["typescript","python"]). Omit to enable all.'),
    disabledPatterns: z.array(z.string()).optional().describe('Pattern IDs to skip during scanning.'),
    minSeverity: z
        .enum(['CRITICAL', 'HIGH', 'MEDIUM'])
        .optional()
        .describe('Minimum severity to report. Valid values: CRITICAL, HIGH, MEDIUM. Default: MEDIUM.'),
    warnThreshold: z
        .number()
        .int()
        .min(0)
        .max(100)
        .optional()
        .describe('Score below this value triggers a warning in update_status (default: 80).'),
});
// ---------------------------------------------------------------------------
// scan_crash_risks
// ---------------------------------------------------------------------------
export async function handleScanCrashRisks(args) {
    const projectPath = args.projectPath;
    if (!projectPath) {
        return {
            content: [
                {
                    type: 'text',
                    text: 'projectPath is required for scan_crash_risks. Provide the absolute path to the project root.',
                },
            ],
            isError: true,
        };
    }
    const report = await scanCrashRisks(projectPath);
    if (report.score >= 80) {
        return {
            content: [
                {
                    type: 'text',
                    text: [
                        `Score: ${String(report.score)}/100 — no critical risks found`,
                        '',
                        `| Metric | Value |`,
                        `|--------|-------|`,
                        `| Scanned files | ${String(report.scannedFiles)} |`,
                        `| Detected stack | ${report.detectedStack.join(', ') || 'none'} |`,
                        `| Scan duration | ${String(report.scanDurationMs)}ms |`,
                    ].join('\n'),
                },
            ],
        };
    }
    const criticalCount = report.risks.filter((r) => r.severity === 'CRITICAL').length;
    const highCount = report.risks.filter((r) => r.severity === 'HIGH').length;
    const mediumCount = report.risks.filter((r) => r.severity === 'MEDIUM').length;
    const lines = [
        `Crash Shield Score: ${String(report.score)}/100`,
        '',
        `| Severity | Count |`,
        `|----------|-------|`,
        `| CRITICAL | ${String(criticalCount)} |`,
        `| HIGH | ${String(highCount)} |`,
        `| MEDIUM | ${String(mediumCount)} |`,
        '',
        `**Risks detected:**`,
        '',
        `| File | Line | Severity | Pattern | Description |`,
        `|------|------|----------|---------|-------------|`,
    ];
    for (const risk of report.risks) {
        const file = risk.file.length > 40 ? `...${risk.file.slice(-37)}` : risk.file;
        lines.push(`| ${file} | ${String(risk.line)} | ${risk.severity} | ${risk.pattern} | ${risk.description} |`);
    }
    lines.push('');
    lines.push('Run `fix_crash_risks` with dryRun:true to preview automatic fixes.');
    return { content: [{ type: 'text', text: lines.join('\n') }] };
}
// ---------------------------------------------------------------------------
// fix_crash_risks
// ---------------------------------------------------------------------------
export async function handleFixCrashRisks(args) {
    const projectPath = args.projectPath;
    if (!projectPath) {
        return {
            content: [
                {
                    type: 'text',
                    text: 'projectPath is required for fix_crash_risks. Provide the absolute path to the project root.',
                },
            ],
            isError: true,
        };
    }
    const dryRun = args.dryRun ?? true;
    // First scan to collect the list of risky files, then fix them
    const report = await scanCrashRisks(projectPath);
    const riskyFiles = [...new Set(report.risks.filter((r) => r.autoFixable).map((r) => r.file))];
    const fixes = await fixCrashRisks(projectPath, riskyFiles, dryRun);
    if (fixes.length === 0) {
        return {
            content: [
                {
                    type: 'text',
                    text: dryRun
                        ? 'No auto-fixable risks found. No changes would be applied.'
                        : 'No auto-fixable risks found. No changes were applied.',
                },
            ],
        };
    }
    const totalApplied = fixes.reduce((sum, f) => sum + f.applied, 0);
    const mode = dryRun ? '(dry run — no files modified)' : '(fixes applied)';
    const lines = [
        `Crash Shield — ${String(totalApplied)} fix(es) ${mode}`,
        '',
        `| File | Fixes |`,
        `|------|-------|`,
    ];
    for (const fix of fixes) {
        lines.push(`| ${fix.file} | ${String(fix.applied)} |`);
    }
    if (dryRun) {
        lines.push('');
        lines.push('Run with dryRun:false to apply these changes.');
    }
    return { content: [{ type: 'text', text: lines.join('\n') }] };
}
// ---------------------------------------------------------------------------
// configure_crash_rules
// ---------------------------------------------------------------------------
const VALID_SEVERITIES = ['CRITICAL', 'HIGH', 'MEDIUM'];
export async function handleConfigureCrashRules(args) {
    if (args.minSeverity !== undefined &&
        !VALID_SEVERITIES.includes(args.minSeverity)) {
        return {
            content: [
                {
                    type: 'text',
                    text: `Invalid minSeverity "${args.minSeverity}". Valid values: CRITICAL, HIGH, MEDIUM.`,
                },
            ],
            isError: true,
        };
    }
    const existing = await getCrashShieldConfig(args.projectId);
    const config = {
        projectId: args.projectId,
        enabledLanguages: args.enabledLanguages ?? existing?.enabledLanguages,
        disabledPatterns: args.disabledPatterns ?? existing?.disabledPatterns,
        minSeverity: args.minSeverity ?? existing?.minSeverity,
        warnThreshold: args.warnThreshold ?? existing?.warnThreshold,
        customPatterns: existing?.customPatterns,
    };
    await saveCrashShieldConfig(config);
    const lines = [
        'Crash Shield rules configured.',
        '',
        '| Setting | Value |',
        '|---------|-------|',
        `| Enabled languages | ${config.enabledLanguages?.join(', ') ?? 'all'} |`,
        `| Disabled patterns | ${config.disabledPatterns?.join(', ') ?? 'none'} |`,
        `| Min severity | ${config.minSeverity ?? 'MEDIUM (default)'} |`,
        `| Warn threshold | ${String(config.warnThreshold ?? 80)} |`,
    ];
    return { content: [{ type: 'text', text: lines.join('\n') }] };
}
//# sourceMappingURL=crash-shield-handler.js.map