"""TS-SQL-001: SQL Injection detection for TypeScript/JavaScript.

Detects raw SQL queries with string interpolation or concatenation
in Node.js/TS MCP servers.
"""

from __future__ import annotations

import re

from . import TSRule
from ..models import Finding, Severity

SQL_KEYWORDS = re.compile(
    r'(?i)\b(SELECT|INSERT|UPDATE|DELETE|DROP|ALTER|CREATE)\s+'
)
TEMPLATE_SQL = re.compile(
    r'(?i)`[^`]*(SELECT|INSERT|UPDATE|DELETE|DROP)\s+[^`]*\$\{[^}]+\}[^`]*`'
)
CONCAT_SQL = re.compile(
    r'''(?i)['"][^'"]*(?:SELECT|INSERT|UPDATE|DELETE|DROP)\s+[^'"]*['"]\s*\+'''
)
QUERY_METHOD = re.compile(
    r'\b(?:query|execute|raw|prepare)\s*\('
)


class TSSqlInjectionRule(TSRule):
    """Detects SQL injection patterns in TypeScript/JavaScript."""

    @property
    def rule_id(self) -> str:
        return "TS-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 with string interpolation or concatenation "
            "allow injection attacks."
        )

    @property
    def detailed_description(self) -> str:
        return (
            "SQL queries with string interpolation or concatenation "
            "allow injection attacks.\n\n"
            "Examples of vulnerable code:\n"
            "  db.query(`SELECT * FROM users WHERE id = ${userId}`);\n"
            "  connection.execute('SELECT * FROM t WHERE name=' + name);\n\n"
            "How to fix:\n"
            "  - Use parameterized queries: db.query('SELECT * FROM users "
            "WHERE id = ?', [userId])\n"
            "  - Use an ORM like Prisma, Drizzle, or TypeORM\n"
            "  - Never concatenate user input into SQL strings"
        )

    def check(self, source: str) -> list[Finding]:
        """Check for SQL injection patterns."""
        findings: list[Finding] = []
        lines = self._get_lines(source)

        for i, line in enumerate(lines, 1):
            if self._is_comment_line(line):
                continue

            # Template literal with SQL + interpolation
            if TEMPLATE_SQL.search(line):
                findings.append(self._make_finding(i, line))
                continue

            # String concatenation with SQL keywords
            if CONCAT_SQL.search(line):
                findings.append(self._make_finding(i, line))
                continue

            # query/execute call with template literal containing ${}
            if QUERY_METHOD.search(line) and '`' in line:
                if '${' in line and SQL_KEYWORDS.search(line):
                    findings.append(self._make_finding(i, line))

        return findings

    def _make_finding(self, lineno: int, line: str) -> Finding:
        """Create a SQL injection finding."""
        return Finding(
            rule_id=self.rule_id,
            severity=self.severity,
            title="Potential SQL Injection",
            description="SQL query with string interpolation or concatenation.",
            file="",
            line=lineno,
            code_snippet=line.strip()[:80],
            recommendation="Use parameterized queries instead.",
            cwe=self.cwe,
            confidence="MEDIUM",
        )
