"""
Staleness Checker — Detects when a CLAUDE.md has gone out of date.

Compares the contents of CLAUDE.md against the current state of the codebase
to identify:
- References to files that no longer exist
- Missing references to new important files
- Changed tech stack (new packages, removed packages)
- Outdated directory structure descriptions
"""

import re
import os
from pathlib import Path
from typing import Optional


class StalenessChecker:
    """Checks CLAUDE.md for staleness against the current codebase."""

    def __init__(self, project_root: str, claude_md_path: str = "CLAUDE.md"):
        self.root = Path(project_root)
        self.claude_md_path = self.root / claude_md_path

    def check(self) -> dict:
        """
        Run staleness analysis.
        Returns a report with staleness score and specific issues.
        """
        if not self.claude_md_path.exists():
            return {
                "score": 100,
                "issues": [],
                "exists": False,
                "message": f"{self.claude_md_path.name} not found. Run 'claudemd generate' to create it.",
            }

        content = self.claude_md_path.read_text(encoding="utf-8", errors="ignore")
        issues = []

        # Run all checks
        issues.extend(self._check_dead_file_refs(content))
        issues.extend(self._check_dead_dir_refs(content))
        issues.extend(self._check_new_significant_files(content))
        issues.extend(self._check_age(content))

        # Calculate staleness score
        score = self._calculate_score(issues)

        return {
            "score": score,
            "issues": issues,
            "exists": True,
            "total_issues": len(issues),
            "critical": sum(1 for i in issues if i["severity"] == "high"),
            "warnings": sum(1 for i in issues if i["severity"] == "medium"),
            "info": sum(1 for i in issues if i["severity"] == "low"),
        }

    def _check_dead_file_refs(self, content: str) -> list[dict]:
        """Find references to files that no longer exist."""
        issues = []

        # Look for file paths in CLAUDE.md (common patterns)
        # Matches: `path/to/file.ext`, path/to/file.ext, `path/to/file`
        patterns = [
            r"`([a-zA-Z0-9_./\\-]+\.[a-zA-Z]{2,5})`",  # backtick quoted paths
            r"\b([a-zA-Z0-9_./\\-]+\.(?:py|ts|js|go|rs|java|md|toml|json|yaml|yml))\b",
        ]

        mentioned_files = set()
        for pattern in patterns:
            matches = re.findall(pattern, content)
            mentioned_files.update(matches)

        # Check which don't exist
        for file_ref in mentioned_files:
            # Skip generic references like "*.py" or very short ones
            if "*" in file_ref or len(file_ref) < 5:
                continue
            # Skip URLs
            if file_ref.startswith(("http", "www")):
                continue

            full_path = self.root / file_ref
            if not full_path.exists():
                issues.append({
                    "type": "dead_file_reference",
                    "severity": "medium",
                    "message": f"References '{file_ref}' which no longer exists",
                    "suggestion": f"Remove or update the reference to '{file_ref}'",
                    "section": self._find_section(content, file_ref),
                })

        return issues

    def _check_dead_dir_refs(self, content: str) -> list[dict]:
        """Find references to directories that no longer exist."""
        issues = []

        # Match `dirname/` patterns
        dir_pattern = r"`([a-zA-Z0-9_-]+)/`"
        mentioned_dirs = re.findall(dir_pattern, content)

        skip_dirs = {"src", "lib", "bin", "pkg", "cmd", "api", "app", "web", "tests", "test",
                     "docs", "doc", "config", "scripts", "tools", "dist", "build"}

        for dir_ref in mentioned_dirs:
            if dir_ref.lower() in skip_dirs:
                continue
            full_path = self.root / dir_ref
            if not full_path.exists():
                issues.append({
                    "type": "dead_dir_reference",
                    "severity": "high",
                    "message": f"References directory '{dir_ref}/' which no longer exists",
                    "suggestion": f"Update or remove the reference to '{dir_ref}/'",
                    "section": self._find_section(content, f"{dir_ref}/"),
                })

        return issues

    def _check_new_significant_files(self, content: str) -> list[dict]:
        """Find new significant files that aren't mentioned."""
        issues = []

        # Look for new significant files in project root
        significant_patterns = [
            "Dockerfile",
            "docker-compose.yml",
            "docker-compose.yaml",
            ".github",
            "Makefile",
            "justfile",
            "pyproject.toml",
            "package.json",
            "tsconfig.json",
            "Cargo.toml",
            "go.mod",
        ]

        for filename in significant_patterns:
            path = self.root / filename
            if path.exists():
                # Check if it's mentioned in CLAUDE.md
                if filename.lower() not in content.lower():
                    issues.append({
                        "type": "missing_significant_file",
                        "severity": "low",
                        "message": f"'{filename}' exists but isn't mentioned in CLAUDE.md",
                        "suggestion": f"Consider adding a note about '{filename}' and its purpose",
                        "section": None,
                    })

        return issues

    def _check_age(self, content: str) -> list[dict]:
        """Check if CLAUDE.md is very old based on file modification time."""
        issues = []

        try:
            import time
            stat = self.claude_md_path.stat()
            age_days = (time.time() - stat.st_mtime) / 86400

            if age_days > 90:
                issues.append({
                    "type": "age",
                    "severity": "low",
                    "message": f"CLAUDE.md was last modified {int(age_days)} days ago",
                    "suggestion": "Run 'claudemd check' to verify it's still accurate",
                    "section": None,
                })
        except Exception:
            pass

        return issues

    def _find_section(self, content: str, term: str) -> Optional[str]:
        """Find which section of CLAUDE.md contains a term."""
        lines = content.split("\n")
        current_section = "top"

        for line in lines:
            if line.startswith("## ") or line.startswith("# "):
                current_section = line.lstrip("#").strip()
            if term.lower() in line.lower():
                return current_section

        return None

    def _calculate_score(self, issues: list[dict]) -> int:
        """
        Calculate staleness score (0 = fresh, 100 = very stale).
        """
        if not issues:
            return 0

        score = 0
        for issue in issues:
            if issue["severity"] == "high":
                score += 20
            elif issue["severity"] == "medium":
                score += 10
            else:
                score += 3

        return min(score, 100)

    def format_report(self, data: dict = None) -> str:
        """Format a human-readable staleness report."""
        if data is None:
            data = self.check()

        if not data["exists"]:
            return data["message"]

        score = data["score"]
        lines = [
            f"Staleness score: {score}/100",
            f"Status: {'FRESH' if score < 20 else 'SLIGHTLY STALE' if score < 40 else 'STALE' if score < 60 else 'VERY STALE'}",
            f"Issues: {data['critical']} critical, {data['warnings']} warnings, {data['info']} info",
        ]

        if data["issues"]:
            lines.append("\nDetails:")
            for issue in sorted(data["issues"], key=lambda x: {"high": 0, "medium": 1, "low": 2}[x["severity"]]):
                icon = "[HIGH]" if issue["severity"] == "high" else "[WARN]" if issue["severity"] == "medium" else "[INFO]"
                lines.append(f"  {icon} {issue['message']}")
                if issue.get("section"):
                    lines.append(f"     Section: {issue['section']}")
                lines.append(f"     Fix: {issue['suggestion']}")

        return "\n".join(lines)
