"""Code reviewer that combines analysis results.

This module provides the main code review functionality,
combining multiple analyzers and generating comprehensive reviews.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from pathlib import Path
from typing import Optional, TYPE_CHECKING

from ieum.review.analyzer import CodeAnalyzer, ReviewIssue, Severity, IssueCategory
from ieum.review.security import SecurityChecker

if TYPE_CHECKING:
    from langchain_core.language_models import BaseChatModel


@dataclass
class ReviewResult:
    """Result of a code review."""

    issues: list[ReviewIssue] = field(default_factory=list)
    summary: str = ""
    score: int = 100  # 0-100 score
    passed: bool = True
    files_reviewed: list[str] = field(default_factory=list)
    statistics: dict = field(default_factory=dict)

    def to_dict(self) -> dict:
        """Convert to dictionary."""
        return {
            "issues": [i.to_dict() for i in self.issues],
            "summary": self.summary,
            "score": self.score,
            "passed": self.passed,
            "files_reviewed": self.files_reviewed,
            "statistics": self.statistics,
        }

    @property
    def critical_count(self) -> int:
        return sum(1 for i in self.issues if i.severity == Severity.CRITICAL)

    @property
    def high_count(self) -> int:
        return sum(1 for i in self.issues if i.severity == Severity.HIGH)

    @property
    def medium_count(self) -> int:
        return sum(1 for i in self.issues if i.severity == Severity.MEDIUM)

    @property
    def low_count(self) -> int:
        return sum(1 for i in self.issues if i.severity == Severity.LOW)

    @property
    def info_count(self) -> int:
        return sum(1 for i in self.issues if i.severity == Severity.INFO)


class CodeReviewer:
    """Main code reviewer combining multiple analysis types."""

    def __init__(self, model: Optional["BaseChatModel"] = None):
        """Initialize the code reviewer.

        Args:
            model: Optional LLM for AI-enhanced review.
        """
        self.model = model
        self.analyzer = CodeAnalyzer()
        self.security_checker = SecurityChecker()

    def review_file(self, file_path: str | Path) -> ReviewResult:
        """Review a single file.

        Args:
            file_path: Path to the file.

        Returns:
            ReviewResult with issues found.
        """
        file_path = Path(file_path)
        result = ReviewResult(files_reviewed=[str(file_path)])

        if not file_path.exists():
            return result

        # Run static analysis
        result.issues.extend(self.analyzer.analyze_file(file_path))

        # Run security checks
        result.issues.extend(self.security_checker.check_file(file_path))

        # Calculate score and summary
        self._finalize_result(result)

        return result

    def review_files(self, file_paths: list[str | Path]) -> ReviewResult:
        """Review multiple files.

        Args:
            file_paths: List of file paths.

        Returns:
            Combined ReviewResult.
        """
        result = ReviewResult()

        for file_path in file_paths:
            file_result = self.review_file(file_path)
            result.issues.extend(file_result.issues)
            result.files_reviewed.extend(file_result.files_reviewed)

        self._finalize_result(result)

        return result

    def review_diff(self, diff: str, file_path: str) -> ReviewResult:
        """Review a git diff.

        Args:
            diff: Git diff content.
            file_path: Path to the file.

        Returns:
            ReviewResult for changed lines.
        """
        result = ReviewResult(files_reviewed=[file_path])

        # Analyze diff for issues
        result.issues.extend(self.analyzer.analyze_diff(diff, file_path))

        # Check security in diff content
        # Extract added lines from diff
        added_lines = []
        for line in diff.split("\n"):
            if line.startswith("+") and not line.startswith("+++"):
                added_lines.append(line[1:])

        if added_lines:
            added_content = "\n".join(added_lines)
            language = self._detect_language(file_path)
            result.issues.extend(
                self.security_checker.check_code(added_content, language, file_path)
            )

        self._finalize_result(result)

        return result

    def review_changes(
        self,
        file_path: str | Path,
        old_content: str,
        new_content: str,
    ) -> ReviewResult:
        """Review changes between old and new content.

        Args:
            file_path: File path.
            old_content: Original content.
            new_content: New content.

        Returns:
            ReviewResult for the changes.
        """
        # For now, just review the new content
        # A more sophisticated implementation would generate a diff
        result = ReviewResult(files_reviewed=[str(file_path)])

        language = self._detect_language(str(file_path))

        # Check new content
        for i, line in enumerate(new_content.split("\n"), 1):
            # Security checks
            issues = self.security_checker.check_code(line, language)
            for issue in issues:
                issue.line = i
                issue.file_path = str(file_path)
                result.issues.append(issue)

        self._finalize_result(result)

        return result

    def suggest_improvements(
        self,
        file_path: str | Path,
        use_ai: bool = True,
    ) -> list[ReviewIssue]:
        """Suggest code improvements using AI.

        Args:
            file_path: Path to the file.
            use_ai: Whether to use AI for suggestions.

        Returns:
            List of improvement suggestions.
        """
        if not use_ai or not self.model:
            # Return basic suggestions from static analysis
            result = self.review_file(file_path)
            return [i for i in result.issues if i.severity in (Severity.LOW, Severity.INFO)]

        try:
            with open(file_path, "r", encoding="utf-8") as f:
                content = f.read()

            # Get AI suggestions
            prompt = f"""Review this code and suggest improvements for:
1. Code quality and maintainability
2. Performance optimizations
3. Better practices

Code:
```
{content[:3000]}  # Limit content
```

Provide specific, actionable suggestions with line numbers when possible.
Format each suggestion as:
- Line X: [suggestion]"""

            response = self.model.invoke(prompt)
            suggestions_text = response.content if hasattr(response, "content") else str(response)

            # Parse AI suggestions into ReviewIssue objects
            suggestions = []
            for line in suggestions_text.split("\n"):
                if line.strip().startswith("- Line"):
                    try:
                        # Parse "- Line X: suggestion"
                        parts = line.split(":", 1)
                        line_num = int(parts[0].replace("- Line", "").strip())
                        suggestion_text = parts[1].strip() if len(parts) > 1 else ""

                        suggestions.append(ReviewIssue(
                            severity=Severity.INFO,
                            category=IssueCategory.MAINTAINABILITY,
                            title="AI Suggestion",
                            description=suggestion_text,
                            file_path=str(file_path),
                            line=line_num,
                            rule_id="ai/suggestion",
                        ))
                    except (ValueError, IndexError):
                        continue

            return suggestions

        except Exception:
            return []

    def _finalize_result(self, result: ReviewResult) -> None:
        """Calculate score and summary for a result."""
        # Calculate score based on issues
        score = 100
        score -= result.critical_count * 25
        score -= result.high_count * 15
        score -= result.medium_count * 5
        score -= result.low_count * 1

        result.score = max(0, score)
        result.passed = result.critical_count == 0 and result.high_count == 0

        # Generate summary
        if not result.issues:
            result.summary = "No issues found. Code looks good!"
        else:
            parts = []
            if result.critical_count:
                parts.append(f"{result.critical_count} critical")
            if result.high_count:
                parts.append(f"{result.high_count} high")
            if result.medium_count:
                parts.append(f"{result.medium_count} medium")
            if result.low_count:
                parts.append(f"{result.low_count} low")
            if result.info_count:
                parts.append(f"{result.info_count} info")

            result.summary = f"Found {len(result.issues)} issues: {', '.join(parts)}"

        # Calculate statistics
        result.statistics = {
            "total_issues": len(result.issues),
            "by_severity": {
                "critical": result.critical_count,
                "high": result.high_count,
                "medium": result.medium_count,
                "low": result.low_count,
                "info": result.info_count,
            },
            "by_category": self._count_by_category(result.issues),
            "files_reviewed": len(result.files_reviewed),
        }

    def _count_by_category(self, issues: list[ReviewIssue]) -> dict:
        """Count issues by category."""
        counts = {}
        for issue in issues:
            category = issue.category.value
            counts[category] = counts.get(category, 0) + 1
        return counts

    def _detect_language(self, file_path: str) -> str:
        """Detect programming language."""
        suffix = Path(file_path).suffix.lower()

        if suffix in (".py", ".pyi"):
            return "python"
        elif suffix in (".cpp", ".cxx", ".cc", ".c", ".h", ".hpp"):
            return "cpp"
        elif suffix in (".js", ".jsx"):
            return "javascript"
        elif suffix in (".ts", ".tsx"):
            return "typescript"

        return "unknown"


# Convenience functions
def review_file(file_path: str | Path) -> dict:
    """Review a file for issues.

    Args:
        file_path: Path to the file.

    Returns:
        Review result dictionary.
    """
    reviewer = CodeReviewer()
    result = reviewer.review_file(file_path)
    return result.to_dict()


def review_files(file_paths: list[str | Path]) -> dict:
    """Review multiple files.

    Args:
        file_paths: List of file paths.

    Returns:
        Combined review result dictionary.
    """
    reviewer = CodeReviewer()
    result = reviewer.review_files(file_paths)
    return result.to_dict()


def check_security(file_path: str | Path) -> list[dict]:
    """Check a file for security issues.

    Args:
        file_path: Path to the file.

    Returns:
        List of security issues.
    """
    checker = SecurityChecker()
    issues = checker.check_file(file_path)
    return [i.to_dict() for i in issues]
