"""
Core auditor — analyzes text for AI writing patterns.
"""

import re
import math
from dataclasses import dataclass, field
from pathlib import Path
from typing import List, Dict, Optional, Union
from .patterns import Pattern, get_patterns, load_custom_patterns


@dataclass
class PatternMatch:
    """A detected pattern with details."""
    name: str
    count: int
    weight: float
    severity: str
    description: str
    suggestion: str
    score_contribution: float
    matches: List[str] = field(default_factory=list)


@dataclass
class AuditResult:
    """Result of an AI text audit."""
    text_length: int
    word_count: int
    score: float  # 0-100 (higher = more AI-like)
    verdict: str  # "likely_human", "possibly_ai", "likely_ai"
    patterns: List[PatternMatch]
    suggestions: List[str]
    details: Dict = field(default_factory=dict)

    def to_dict(self) -> Dict:
        """Convert to dictionary for JSON output."""
        return {
            "text_length": self.text_length,
            "word_count": self.word_count,
            "score": round(self.score, 1),
            "verdict": self.verdict,
            "patterns": [
                {
                    "name": p.name,
                    "count": p.count,
                    "weight": p.weight,
                    "severity": p.severity,
                    "description": p.description,
                    "suggestion": p.suggestion,
                    "score_contribution": round(p.score_contribution, 2),
                    "sample_matches": p.matches[:3],
                }
                for p in self.patterns
            ],
            "suggestions": self.suggestions,
            "details": self.details,
        }


class Auditor:
    """AI writing pattern auditor."""

    def __init__(
        self,
        patterns_file: Optional[str] = None,
        language: str = "all",
        threshold_ai: float = 60.0,
        threshold_possible: float = 30.0,
    ):
        """
        Initialize the auditor.

        Args:
            patterns_file: Path to custom patterns YAML file.
            language: "en", "zh", or "all".
            threshold_ai: Score above this = "likely_ai".
            threshold_possible: Score above this = "possibly_ai".
        """
        self.patterns = get_patterns(language)
        self.threshold_ai = threshold_ai
        self.threshold_possible = threshold_possible

        if patterns_file:
            custom = load_custom_patterns(patterns_file)
            self.patterns.extend(custom)

    def analyze(self, text: str) -> AuditResult:
        """
        Analyze text for AI writing patterns.

        Args:
            text: The text to analyze.

        Returns:
            AuditResult with score, verdict, and pattern details.
        """
        if not text or not text.strip():
            return AuditResult(
                text_length=0, word_count=0, score=0.0,
                verdict="likely_human", patterns=[], suggestions=[],
                details={"error": "Empty text"}
            )

        word_count = len(text.split())
        text_length = len(text)

        # Detect patterns
        matches = []
        total_score = 0.0
        all_suggestions = []

        for pattern in self.patterns:
            found = pattern.findall(text)
            if found:
                # Normalize count by text length (per 500 words)
                raw_count = len(found)
                normalized_count = raw_count * (500 / max(word_count, 1))
                contribution = min(normalized_count * pattern.weight * 10, 30)

                match = PatternMatch(
                    name=pattern.name,
                    count=raw_count,
                    weight=pattern.weight,
                    severity=pattern.severity,
                    description=pattern.description,
                    suggestion=pattern.suggestion,
                    score_contribution=contribution,
                    matches=found[:5],
                )
                matches.append(match)
                total_score += contribution

                if pattern.suggestion and pattern.suggestion not in all_suggestions:
                    all_suggestions.append(pattern.suggestion)

        # Cap score at 100
        score = min(total_score, 100.0)

        # Determine verdict
        if score >= self.threshold_ai:
            verdict = "likely_ai"
        elif score >= self.threshold_possible:
            verdict = "possibly_ai"
        else:
            verdict = "likely_human"

        # Sort patterns by score contribution (highest first)
        matches.sort(key=lambda m: m.score_contribution, reverse=True)

        return AuditResult(
            text_length=text_length,
            word_count=word_count,
            score=round(score, 1),
            verdict=verdict,
            patterns=matches,
            suggestions=all_suggestions[:10],
            details={
                "language": "mixed",
                "patterns_checked": len(self.patterns),
                "patterns_matched": len(matches),
            }
        )

    def analyze_file(self, path: Union[str, Path]) -> AuditResult:
        """Analyze a file."""
        path = Path(path)
        text = path.read_text(encoding="utf-8", errors="replace")
        result = self.analyze(text)
        result.details["file"] = str(path)
        return result

    def analyze_dir(self, dir_path: Union[str, Path], extensions: Optional[List[str]] = None) -> List[AuditResult]:
        """Analyze all text files in a directory."""
        dir_path = Path(dir_path)
        if extensions is None:
            extensions = [".md", ".txt", ".rst", ".html", ".tex", ".py", ".js", ".json"]

        results = []
        for ext in extensions:
            for f in dir_path.rglob(f"*{ext}"):
                if f.is_file():
                    try:
                        result = self.analyze_file(f)
                        results.append(result)
                    except Exception:
                        pass
        return results
