"use strict";
/**
 * AI Response Parsing Utilities
 *
 * Functions for parsing validation responses from AI models.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseAIResponse = parseAIResponse;
exports.parseValidationResponse = parseValidationResponse;
exports.parseMultiFileValidationResponse = parseMultiFileValidationResponse;
exports.applyValidationResults = applyValidationResults;
exports.validateSeverity = validateSeverity;
exports.validateCategory = validateCategory;
exports.getLineContent = getLineContent;
const path_helpers_1 = require("./path-helpers");
/**
 * Extract the first top-level JSON array from text.
 * The model may include prose before/after the JSON.
 */
function extractTopLevelArray(text) {
    const startIndex = text.indexOf('[');
    if (startIndex === -1)
        return null;
    let depth = 0;
    let inString = false;
    let stringChar = null;
    let escape = false;
    for (let i = startIndex; i < text.length; i++) {
        const ch = text[i];
        if (inString) {
            if (escape) {
                escape = false;
                continue;
            }
            if (ch === '\\') {
                escape = true;
                continue;
            }
            if (stringChar && ch === stringChar) {
                inString = false;
                stringChar = null;
            }
            continue;
        }
        if (ch === '"' || ch === "'") {
            inString = true;
            stringChar = ch;
            continue;
        }
        if (ch === '[') {
            depth++;
        }
        else if (ch === ']') {
            depth--;
            if (depth === 0) {
                return text.slice(startIndex, i + 1);
            }
        }
    }
    return null;
}
/**
 * Parse AI response for single file validation
 */
function parseAIResponse(response) {
    try {
        // Try to extract JSON from the response
        const jsonMatch = response.match(/\[[\s\S]*\]/);
        if (!jsonMatch) {
            return [];
        }
        const parsed = JSON.parse(jsonMatch[0]);
        // Validate the structure
        if (!Array.isArray(parsed)) {
            return [];
        }
        return parsed.filter(item => typeof item.lineNumber === 'number' &&
            typeof item.severity === 'string' &&
            typeof item.category === 'string' &&
            typeof item.title === 'string' &&
            typeof item.description === 'string').map(item => ({
            lineNumber: item.lineNumber,
            severity: validateSeverity(item.severity),
            category: validateCategory(item.category),
            title: item.title,
            description: item.description,
            suggestedFix: item.suggestedFix || 'Review and fix the security issue',
        }));
    }
    catch (error) {
        console.error('Failed to parse AI response:', error);
        return [];
    }
}
/**
 * Parse single-file validation response
 */
function parseValidationResponse(response) {
    try {
        const jsonSlice = extractTopLevelArray(response);
        if (!jsonSlice)
            return [];
        const parsed = JSON.parse(jsonSlice);
        if (!Array.isArray(parsed))
            return [];
        return parsed
            .filter(item => typeof item.index === 'number' &&
            typeof item.keep === 'boolean')
            .map(item => {
            // Normalize notes field: prefer new 'notes', fallback to legacy 'reason' or 'validationNotes'
            const notes = item.notes || item.validationNotes || item.reason || undefined;
            return {
                index: item.index,
                keep: item.keep,
                notes,
                adjustedSeverity: item.adjustedSeverity || null,
                // Keep legacy fields for backward compatibility
                reason: item.reason,
                validationNotes: item.validationNotes,
                // Actionable output fields (PRO-82)
                impact: item.impact || undefined,
                fixSuggestion: item.fixSuggestion || undefined,
            };
        });
    }
    catch (error) {
        console.error('Failed to parse validation response:', error);
        return [];
    }
}
/**
 * Parse multi-file validation response (Phase 2)
 * Returns a map of file path -> validation results
 */
function parseMultiFileValidationResponse(response, expectedFiles) {
    const resultMap = new Map();
    try {
        const jsonSlice = extractTopLevelArray(response);
        if (!jsonSlice) {
            console.error('[AI Validation] Multi-file: No JSON array found in response');
            return resultMap;
        }
        const parsed = JSON.parse(jsonSlice);
        if (!Array.isArray(parsed)) {
            console.error('[AI Validation] Multi-file: Parsed result is not an array');
            return resultMap;
        }
        // Process each file's results
        for (const fileResult of parsed) {
            if (!fileResult.file || !Array.isArray(fileResult.validations)) {
                console.warn('[AI Validation] Multi-file: Invalid file result structure, skipping');
                continue;
            }
            // Use path normalization to match AI response paths to expected paths
            const responsePath = fileResult.file;
            const matchedPath = (0, path_helpers_1.findMatchingFilePath)(responsePath, expectedFiles);
            if (!matchedPath) {
                console.warn(`[AI Validation] Multi-file: Could not match path "${responsePath}" to any expected file`);
                continue;
            }
            const validations = fileResult.validations
                .filter((item) => typeof item.index === 'number' &&
                typeof item.keep === 'boolean')
                .map((item) => {
                // Normalize notes field: prefer new 'notes', fallback to legacy 'reason' or 'validationNotes'
                const notes = item.notes || item.validationNotes || item.reason || undefined;
                return {
                    index: item.index,
                    keep: item.keep,
                    notes,
                    adjustedSeverity: item.adjustedSeverity || null,
                    // Keep legacy fields for backward compatibility
                    reason: item.reason,
                    validationNotes: item.validationNotes,
                    // Actionable output fields (PRO-82)
                    impact: item.impact || undefined,
                    fixSuggestion: item.fixSuggestion || undefined,
                };
            });
            resultMap.set(matchedPath, validations);
        }
        // Log any files that weren't in the response (these will be REJECTED by default)
        const missingFiles = expectedFiles.filter(f => !resultMap.has(f));
        if (missingFiles.length > 0) {
            console.warn(`[AI Validation] Multi-file: Missing ${missingFiles.length} files from response: ${missingFiles.join(', ')}`);
        }
    }
    catch (error) {
        console.error('[AI Validation] Multi-file: Failed to parse response:', error);
    }
    return resultMap;
}
/**
 * Apply validation results to findings
 */
function applyValidationResults(findings, validationResults) {
    const processed = [];
    let dismissedCount = 0;
    for (let i = 0; i < findings.length; i++) {
        const finding = findings[i];
        const validation = validationResults.find(v => v.index === i);
        if (!validation) {
            // No validation result - REJECT by default (conservative approach)
            // If AI doesn't explicitly validate a finding, assume it's a false positive
            console.warn(`[AI Validation] No result for finding ${i}: ${finding.title} - REJECTING`);
            dismissedCount++;
            continue; // Don't add to processed - finding is removed
        }
        if (validation.keep) {
            // Keep the finding
            const adjustedFinding = {
                ...finding,
                validatedByAI: true,
                confidence: 'high',
            };
            // Extract notes from optimized or legacy format
            const validationNotes = validation.notes || validation.validationNotes || validation.reason || undefined;
            if (validation.adjustedSeverity && validation.adjustedSeverity !== finding.severity) {
                // Severity was adjusted
                adjustedFinding.originalSeverity = finding.severity;
                adjustedFinding.severity = validation.adjustedSeverity;
                adjustedFinding.validationStatus = 'downgraded';
                adjustedFinding.validationNotes = validationNotes || 'Severity adjusted by AI validation';
            }
            else {
                // Confirmed at original severity
                adjustedFinding.validationStatus = 'confirmed';
                adjustedFinding.validationNotes = validationNotes;
            }
            // Apply AI-generated actionable fields (PRO-82)
            if (validation.impact) {
                adjustedFinding.impact = validation.impact;
                adjustedFinding.aiEnhanced = true;
            }
            if (validation.fixSuggestion) {
                // AI-generated fix becomes the primary fix step
                adjustedFinding.fixSteps = [validation.fixSuggestion];
                adjustedFinding.aiEnhanced = true;
            }
            processed.push(adjustedFinding);
        }
        else {
            // Finding was dismissed - only log in debug mode to reduce noise
            if (process.env.DEBUG || process.env.OCULUM_DEBUG) {
                console.log(`[AI Validation] Rejected: ${finding.title} at ${finding.filePath}:${finding.lineNumber}`);
            }
            dismissedCount++;
            // Don't add to processed - finding is removed
        }
    }
    return { processed, dismissedCount };
}
/**
 * Validate severity value from AI response
 */
function validateSeverity(severity) {
    const valid = ['critical', 'high', 'medium', 'low', 'info'];
    return valid.includes(severity)
        ? severity
        : 'medium';
}
/**
 * Validate category value from AI response
 */
function validateCategory(category) {
    const valid = [
        'sql_injection', 'xss', 'command_injection', 'missing_auth',
        'dangerous_function', 'hardcoded_secret', 'high_entropy_string',
        'sensitive_variable', 'security_bypass', 'insecure_config',
        'suspicious_package', 'cors_misconfiguration', 'root_container',
        'weak_crypto', 'sensitive_url', 'ai_pattern', 'dangerous_file',
        'data_exposure', // For logging/exposing sensitive data
        'ai_skill_injection',
    ];
    return valid.includes(category)
        ? category
        : 'dangerous_function';
}
/**
 * Get line content from file content by line number
 */
function getLineContent(content, lineNumber) {
    const lines = content.split('\n');
    return lines[lineNumber - 1]?.trim() || '';
}
//# sourceMappingURL=response-parser.js.map