// P1: json.loads without try/except — CRITICAL
const JSON_LOADS = /\bjson\.loads\s*\(/;
const TRY_EXCEPT = /\btry\s*:/;
// P2: Direct dict access without .get() — HIGH
const DICT_BRACKET_ACCESS = /(\w+)\['[^']+'\]/;
const JSON_REQUEST_CONTEXT = /(?:json\.loads|request\.|environ|\.json\(\))/;
// P3: os.environ without .get() — HIGH
const ENVIRON_BRACKET = /os\.environ\['[^']+'\]/;
// P4: requests.json() chained — HIGH
const REQUESTS_CHAINED = /requests\.\w+\([^)]+\)\.json\(\)/;
// P5: int/float() without try/except in user-input context — MEDIUM
const INT_FLOAT_CALL = /\b(?:int|float)\s*\(/;
const USER_INPUT_CONTEXT = /(?:input\(|request\.|argv|environ|sys\.argv)/;
function splitLines(content) {
    return content.split('\n');
}
function hasTryCatchInScope(content, lineIndex) {
    const lines = splitLines(content);
    const windowStart = Math.max(0, lineIndex - 5);
    const windowEnd = Math.min(lines.length - 1, lineIndex + 5);
    for (let i = windowStart; i <= windowEnd; i++) {
        if (TRY_EXCEPT.test(lines[i] ?? '')) {
            return true;
        }
    }
    return false;
}
function detectP1(filePath, content) {
    const risks = [];
    const lines = splitLines(content);
    for (let i = 0; i < lines.length; i++) {
        const line = lines[i] ?? '';
        if (JSON_LOADS.test(line) && !hasTryCatchInScope(content, i)) {
            risks.push({
                file: filePath,
                line: i + 1,
                pattern: 'PYTHON_JSON_LOADS_NO_TRY',
                severity: 'CRITICAL',
                description: 'json.loads() called without surrounding try/except. Malformed JSON raises json.JSONDecodeError.',
                suggestedFix: 'Wrap json.loads() in try/except json.JSONDecodeError.',
                autoFixable: false,
            });
        }
    }
    return risks;
}
function detectP2(filePath, content) {
    const risks = [];
    if (!JSON_REQUEST_CONTEXT.test(content)) {
        return risks;
    }
    const lines = splitLines(content);
    for (let i = 0; i < lines.length; i++) {
        const line = lines[i] ?? '';
        if (DICT_BRACKET_ACCESS.test(line) && !line.includes('.get(')) {
            risks.push({
                file: filePath,
                line: i + 1,
                pattern: 'PYTHON_DICT_BRACKET_ACCESS',
                severity: 'HIGH',
                description: 'Direct dict key access dict["key"] raises KeyError if key is missing. Common in JSON/request parsing contexts.',
                suggestedFix: 'Use dict.get("key") or dict.get("key", default) to avoid KeyError.',
                autoFixable: false,
            });
        }
    }
    return risks;
}
function detectP3(filePath, content) {
    const risks = [];
    const lines = splitLines(content);
    for (let i = 0; i < lines.length; i++) {
        const line = lines[i] ?? '';
        if (ENVIRON_BRACKET.test(line)) {
            risks.push({
                file: filePath,
                line: i + 1,
                pattern: 'PYTHON_ENVIRON_NO_DEFAULT',
                severity: 'HIGH',
                description: 'os.environ["KEY"] raises KeyError if env variable is not set. Crashes at startup if variable is missing.',
                suggestedFix: 'Use os.environ.get("KEY") or os.environ.get("KEY", "default").',
                autoFixable: false,
            });
        }
    }
    return risks;
}
function detectP4(filePath, content) {
    const risks = [];
    const lines = splitLines(content);
    for (let i = 0; i < lines.length; i++) {
        const line = lines[i] ?? '';
        if (REQUESTS_CHAINED.test(line)) {
            risks.push({
                file: filePath,
                line: i + 1,
                pattern: 'PYTHON_REQUESTS_JSON_CHAINED',
                severity: 'HIGH',
                description: 'Chained requests.get(...).json() can raise json.JSONDecodeError if response is not JSON (e.g., 500 HTML error page).',
                suggestedFix: 'Check response.ok and call response.json() separately in a try/except block.',
                autoFixable: false,
            });
        }
    }
    return risks;
}
function detectP5(filePath, content) {
    const risks = [];
    if (!USER_INPUT_CONTEXT.test(content)) {
        return risks;
    }
    const lines = splitLines(content);
    for (let i = 0; i < lines.length; i++) {
        const line = lines[i] ?? '';
        if (INT_FLOAT_CALL.test(line) && !hasTryCatchInScope(content, i)) {
            risks.push({
                file: filePath,
                line: i + 1,
                pattern: 'PYTHON_INT_FLOAT_NO_TRY',
                severity: 'MEDIUM',
                description: 'int() or float() conversion without try/except raises ValueError on invalid user input.',
                suggestedFix: 'Wrap int()/float() in try/except ValueError.',
                autoFixable: false,
            });
        }
    }
    return risks;
}
export const pythonDetector = {
    language: 'Python',
    fileExtensions: ['.py'],
    detect(filePath, content) {
        return [
            ...detectP1(filePath, content),
            ...detectP2(filePath, content),
            ...detectP3(filePath, content),
            ...detectP4(filePath, content),
            ...detectP5(filePath, content),
        ];
    },
};
//# sourceMappingURL=python-detector.js.map