"""SEC-001: Hardcoded Secrets detection rule."""

from __future__ import annotations

import ast
import re

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

SECRET_PATTERNS = [
    (r'(?i)(api[_-]?key|secret|token|password|passwd|pwd)\s*=\s*["\'][^"\']{8,}["\']',
     "Posible secret hardcodeado"),
    (r'(?i)(sk-[a-zA-Z0-9]{20,})', "API key de Anthropic/OpenAI"),
    (r'(?i)(ghp_[a-zA-Z0-9]{36})', "GitHub Personal Access Token"),
    (r'(?i)(xoxb-[a-zA-Z0-9-]+)', "Slack Bot Token"),
]


class HardcodedSecretsRule(Rule):
    """Detects hardcoded secrets, API keys, and tokens."""

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

    @property
    def name(self) -> str:
        return "Hardcoded Secrets"

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

    @property
    def description(self) -> str:
        return "Hardcoded secrets, API keys, or tokens detected in source code."

    def suggest_fix(self, source, finding):
        """Replace hardcoded secret with os.environ.get() call."""
        lines = source.splitlines()
        idx = finding.line - 1
        if idx < 0 or idx >= len(lines):
            return None
        line = lines[idx]
        var_match = re.match(r'^\s*(\w+)', line)
        if not var_match:
            return None
        var_name = var_match.group(1)
        indent = line[: len(line) - len(line.lstrip())]
        assign_pat = re.compile(r'\w+\s*=\s*[\x22\x27]')
        if assign_pat.search(line):
            return indent + var_name + ' = os.environ.get(' + repr(var_name) + ', ' + repr('') + ')'
        return None

    def check(self, tree: ast.Module, source: str) -> list[Finding]:
        """Check for hardcoded secrets in source lines."""
        findings: list[Finding] = []
        lines = self._get_lines(source)

        for i, line in enumerate(lines, 1):
            for pattern, desc in SECRET_PATTERNS:
                if not re.search(pattern, line):
                    continue
                stripped = line.strip()
                if stripped.startswith("#") or "example" in stripped.lower():
                    continue
                findings.append(Finding(
                    rule_id=self.rule_id,
                    severity=self.severity,
                    title="Secret Hardcodeado",
                    description=f"{desc} detectado en linea {i}.",
                    file="",
                    line=i,
                    code_snippet=stripped[:80] + "..." if len(stripped) > 80 else stripped,
                    recommendation="Usar variables de entorno: os.environ.get('API_KEY')",
                    cwe="CWE-798",
                    confidence="MEDIUM",
                ))
        return findings
