"""SQL-001: SQL Injection detection rule."""

from __future__ import annotations

import ast
import re

from . import Rule
from ..models import Finding, Severity


class SqlInjectionRule(Rule):
    """Detects SQL queries with string interpolation."""

    @property
    def rule_id(self) -> str:
        return "SQL-001"

    @property
    def name(self) -> str:
        return "SQL Injection"

    @property
    def severity(self) -> Severity:
        return Severity.CRITICAL

    @property
    def cwe(self) -> str:
        return "CWE-89"

    @property
    def description(self) -> str:
        return "SQL queries constructed with string interpolation allow injection."

    @property
    def detailed_description(self) -> str:
        return (
            "SQL queries constructed with string interpolation allow injection.\n\n"
            "SQL injection occurs when user-supplied data is concatenated or\n"
            "interpolated directly into SQL query strings. An attacker can\n"
            "manipulate the query to read, modify, or delete arbitrary data.\n\n"
            "Examples of vulnerable code:\n"
            '  cursor.execute(f"SELECT * FROM users WHERE id={uid}")\n'
            '  cursor.execute("DELETE FROM orders WHERE id=%s" % order_id)\n'
            '  db.query("SELECT * FROM t WHERE name=\'{}\'".format(name))\n\n'
            "How to fix:\n"
            "  - Use parameterized queries: cursor.execute('SELECT * FROM users WHERE id=?', (uid,))\n"
            "  - Use an ORM (SQLAlchemy, Django ORM) that handles escaping\n"
            "  - Never concatenate user input into SQL strings"
        )

    def check(self, tree: ast.Module, source: str) -> list[Finding]:
        """Check for SQL queries with string formatting."""
        findings: list[Finding] = []
        sql_pattern = re.compile(r'(?i)(SELECT|INSERT|UPDATE|DELETE|DROP)\s+')
        lines = self._get_lines(source)

        for i, line in enumerate(lines, 1):
            if not sql_pattern.search(line):
                continue
            has_interpolation = (
                "%" in line
                or "format(" in line
                or "f'" in line
                or 'f"' in line
            )
            if has_interpolation:
                findings.append(Finding(
                    rule_id=self.rule_id,
                    severity=self.severity,
                    title="Potential SQL Injection",
                    description="SQL query constructed with string interpolation.",
                    file="",
                    line=i,
                    code_snippet=line.strip()[:80],
                    recommendation="Use parameterized queries instead.",
                    cwe="CWE-89",
                    confidence="MEDIUM",
                ))
        return findings
