"""Validator — Kural motoru ve tarama."""

import ast
from pathlib import Path

try:
    from ..core.registry import FunctionContract, Registry
    from .base_rules import BASE_RULES, Violation
except ImportError:
    from registry import FunctionContract, Registry
    from base_rules import BASE_RULES, Violation


SUSPICION_SCORES = {
    "SEC001": 40,
    "SEC002": 35,
    "AI001": 30,
    "AI002": 15,
    "AI003": 10,
    "AI004": 25,
    "AI005": 30,
    "AI006": 10,
    "AI007": 5,
    "AI008": 25,
    "AI009": 30,
    "AI010": 20,
    "ARCH001": 20,
    "ARCH002": 15,
    "ARCH003": 10,
    "ARCH004": 5,
    "PERF001": 25,
    "PERF002": 25,
    "PERF003": 20,
    "DUP001": 10,
    "DUP002": 10,
    "DUP003": 15,
    "DUP004": 15,
    "DOM001": 15,
    "DOM002": 20,
    "DOM003": 15,
    "STYLE001": 5,
    "STYLE002": 10,
    "DEAD001": 25,
    "IMP001": 10,
    "ARCH001v2": 25,
    "MISS001": 25,
}


def calculate_suspicion_score(violations: list) -> dict:
    """Şüphe skoru hesapla."""
    if not violations:
        return {
            "total": 0,
            "level": "clean",
            "message": "Kod temiz görünüyor!",
            "breakdown": {},
        }

    breakdown = {}
    for v in violations:
        rule_id = v.rule_id if hasattr(v, "rule_id") else str(v)
        score = SUSPICION_SCORES.get(rule_id, 10)
        breakdown[rule_id] = breakdown.get(rule_id, 0) + score

    total = sum(breakdown.values())

    if total >= 100:
        level = "danger"
        message = "[DANGER] Cok supheyli! Bu kodu yazan AI muhtemelen hata yapiyor."
    elif total >= 50:
        level = "warning"
        message = "[WARNING] Supheyli kod. Lutfen gozden gecir."
    elif total >= 25:
        level = "caution"
        message = "[CAUTION] Birkac sorun var ama tolere edilebilir."
    else:
        level = "clean"
        message = "[OK] Kod temiz gorunuyor."

    return {"total": total, "level": level, "message": message, "breakdown": breakdown}


class Validator:
    def __init__(self, registry: Registry):
        self.registry = registry

    def validate(self, contract: FunctionContract, source: str = "") -> list[Violation]:
        violations = []
        for rule in BASE_RULES:
            try:
                result = rule(contract, self.registry, source)
                if result:
                    violations.append(result)
            except Exception:
                pass
        return violations

    def validate_with_suspicion(
        self, contract: FunctionContract, source: str = ""
    ) -> dict:
        """Violation'lar + şüphe skoru."""
        violations = self.validate(contract, source)
        suspicion = calculate_suspicion_score(violations)
        return {"violations": violations, "suspicion": suspicion}

    def _find_unregistered(self, tree, filepath) -> list[Violation]:
        """EKSİK 1 — @ai_func olmayan fonksiyonları yakala."""
        violations = []
        skip_prefixes = ("test_", "_")
        skip_names = {"main", "setup", "teardown", "setUp", "tearDown", "run", "start"}
        for node in ast.walk(tree):
            if not isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
                continue
            name = node.name
            if any(name.startswith(p) for p in skip_prefixes):
                continue
            if name in skip_names:
                continue
            if name.startswith("__") and name.endswith("__"):
                continue
            # decorator kontrolü
            has_contract = self.registry.get(name) is not None
            has_decorator = any(
                (
                    isinstance(d, ast.Call)
                    and isinstance(d.func, (ast.Name, ast.Attribute))
                    and (d.func.id if isinstance(d.func, ast.Name) else d.func.attr)
                    == "ai_func"
                )
                or (isinstance(d, ast.Name) and d.id == "ai_func")
                for d in node.decorator_list
            )
            if not has_contract and not has_decorator:
                violations.append(
                    Violation(
                        rule_id="MISS001",
                        severity="info",
                        confidence=0.90,
                        message=f"'{name}' kayıtsız — @ai_func decorator'ı yok.",
                        location=f"{filepath}:{node.lineno}",
                        suggestion="@ai_func(domain='...') ekle veya kasıtlıysa _ prefix kullan.",
                        func_name=name,
                    )
                )
        return violations

    def scan_file(self, filepath: str) -> list[Violation]:
        violations = []
        path = Path(filepath)
        if not path.exists():
            return violations
        source = path.read_text(encoding="utf-8")
        try:
            tree = ast.parse(source)
        except SyntaxError as e:
            return [
                Violation(
                    "PARSE001",
                    "error",
                    1.0,
                    f"Syntax hatası: {e}",
                    filepath,
                    "Önce syntax hatasını düzelt.",
                )
            ]

        lines = source.splitlines()
        violations.extend(self._find_unregistered(tree, filepath))

        for node in ast.walk(tree):
            if not isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
                continue
            contract = self.registry.get(node.name)
            if not contract:
                continue
            end = getattr(node, "end_lineno", node.lineno + 30)
            func_source = "\n".join(lines[node.lineno - 1 : end])
            violations.extend(self.validate(contract, func_source))

        return violations

    def scan_project(self, project_root: str = ".") -> list[Violation]:
        violations = []
        for path in Path(project_root).rglob("*.py"):
            if any(
                p.startswith((".", "__pycache__", "venv", "env")) for p in path.parts
            ):
                continue
            violations.extend(self.scan_file(str(path)))
        return violations

    def check_empty_domains(self) -> list[Violation]:
        return [
            Violation(
                "DOM_EMPTY",
                "info",
                1.0,
                f"'{d.name}' domain'i sahipsiz.",
                "aicontract.yaml",
                f"domain='{d.name}' olan bir fonksiyon yaz.",
            )
            for d in self.registry.empty_domains()
        ]
