"""
Git Analyzer — Extracts useful information from git history.

Provides:
- Recently modified files (activity patterns)
- Most frequently changed files (hot spots)
- Author count and collaboration patterns
- Git workflow hints (branching strategy, commit frequency)
"""

import subprocess
import os
from pathlib import Path
from collections import Counter
from typing import Optional


class GitAnalyzer:
    """Analyzes git history for project context."""

    def __init__(self, project_root: str):
        self.root = Path(project_root)

    def _run_git(self, args: list[str], timeout: int = 15) -> Optional[str]:
        """Run a git command and return stdout."""
        try:
            result = subprocess.run(
                ["git"] + args,
                cwd=str(self.root),
                capture_output=True,
                text=True,
                timeout=timeout,
            )
            if result.returncode == 0:
                return result.stdout.strip()
        except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
            pass
        return None

    def is_git_repo(self) -> bool:
        """Check if this is a git repository."""
        return (self.root / ".git").exists() or self._run_git(["rev-parse", "--git-dir"]) is not None

    def get_recently_modified(self, n: int = 20) -> list[str]:
        """Get the N most recently modified files."""
        output = self._run_git(["log", "--name-only", "--pretty=format:", "-50"])
        if not output:
            return []

        files = [
            line.strip()
            for line in output.split("\n")
            if line.strip() and not line.strip().startswith(" ")
        ]

        # Deduplicate while preserving order
        seen = set()
        unique = []
        for f in files:
            if f not in seen:
                seen.add(f)
                unique.append(f)

        return unique[:n]

    def get_hottest_files(self, n: int = 10) -> list[tuple[str, int]]:
        """Get the N most frequently changed files (hot spots)."""
        output = self._run_git([
            "log", "--name-only", "--pretty=format:",
            "--since=3 months ago",
        ])
        if not output:
            return []

        files = [
            line.strip()
            for line in output.split("\n")
            if line.strip()
        ]

        counts = Counter(files)
        return counts.most_common(n)

    def get_commit_stats(self) -> dict:
        """Get overall commit statistics."""
        stats = {
            "total_commits": 0,
            "authors": [],
            "age_days": 0,
            "default_branch": "main",
            "recent_commit_message": "",
        }

        # Total commits
        output = self._run_git(["rev-list", "--count", "HEAD"])
        if output:
            try:
                stats["total_commits"] = int(output)
            except ValueError:
                pass

        # Authors
        output = self._run_git(["log", "--format=%aN", "--no-merges"])
        if output:
            authors = list(dict.fromkeys(output.split("\n")))  # Unique, ordered
            stats["authors"] = authors[:10]

        # Repo age
        output = self._run_git(["log", "--reverse", "--format=%cr", "--max-count=1"])
        if output:
            stats["age_days"] = output

        # Default branch
        for branch in ["main", "master", "develop"]:
            check = self._run_git(["branch", "--list", branch])
            if check:
                stats["default_branch"] = branch
                break

        # Most recent commit message
        output = self._run_git(["log", "-1", "--pretty=%s"])
        if output:
            stats["recent_commit_message"] = output

        return stats

    def get_branch_info(self) -> dict:
        """Get information about branch patterns."""
        output = self._run_git(["branch", "-a"])
        if not output:
            return {"strategy": "unknown", "branch_count": 0}

        branches = [b.strip().lstrip("* ") for b in output.split("\n") if b.strip()]
        total = len(branches)

        # Try to detect branching strategy
        feature_prefixes = sum(1 for b in branches if b.startswith(("feature/", "feat/")))
        fix_prefixes = sum(1 for b in branches if b.startswith(("fix/", "bugfix/", "hotfix/")))
        release_branches = sum(1 for b in branches if "release" in b.lower())

        if feature_prefixes + fix_prefixes > 3:
            strategy = "Git Flow" if release_branches > 0 else "Feature branching (trunk-based)"
        elif total <= 2:
            strategy = "Trunk-based (single branch)"
        else:
            strategy = "Multi-branch"

        return {
            "strategy": strategy,
            "branch_count": total,
            "feature_branches": feature_prefixes,
        }

    def get_gitignore_summary(self) -> list[str]:
        """Get the key patterns from .gitignore."""
        gitignore = self.root / ".gitignore"
        if not gitignore.exists():
            return []

        content = gitignore.read_text(encoding="utf-8", errors="ignore")
        lines = [
            line.strip()
            for line in content.split("\n")
            if line.strip() and not line.startswith("#")
        ]
        return lines[:20]

    def analyze(self) -> dict:
        """Run full git analysis."""
        if not self.is_git_repo():
            return {"is_git_repo": False}

        return {
            "is_git_repo": True,
            "commit_stats": self.get_commit_stats(),
            "branch_info": self.get_branch_info(),
            "recently_modified": self.get_recently_modified(15),
            "hot_spots": self.get_hottest_files(8),
            "gitignore": self.get_gitignore_summary(),
        }

    def to_summary(self) -> str:
        """Return a human-readable git summary."""
        data = self.analyze()
        if not data.get("is_git_repo"):
            return "Not a git repository"

        stats = data.get("commit_stats", {})
        branch = data.get("branch_info", {})

        lines = [
            f"Git: {stats.get('total_commits', '?')} commits",
            f"Authors: {len(stats.get('authors', []))}",
            f"Branch strategy: {branch.get('strategy', 'unknown')}",
            f"Default branch: {stats.get('default_branch', 'main')}",
        ]

        hot = data.get("hot_spots", [])
        if hot:
            hot_str = ", ".join(f[0] for f, _ in hot[:4])
            lines.append(f"Most changed: {hot_str}")

        return "\n".join(lines)
