"""
Git Memory — extracts commit history and authorship data for indexed modules.

Uses subprocess git calls (no extra deps). All operations are read-only.
Falls back gracefully when git is unavailable or repo has no history.
"""

from __future__ import annotations

import subprocess
from pathlib import Path
from typing import Optional


def is_git_repo(path: str) -> bool:
    """Check if the given path is inside a git repository."""
    try:
        r = subprocess.run(
            ["git", "rev-parse", "--git-dir"],
            cwd=path, capture_output=True, text=True, timeout=5,
        )
        return r.returncode == 0
    except Exception:
        return False


def collect_file_histories(repo_root: str) -> dict[str, dict]:
    """
    Collect git history for all files in one efficient pass.

    Runs a single `git log` and builds a per-file map with:
      - commit_count   : number of commits touching this file
      - last_commit    : short hash of the most recent commit
      - last_author    : name of the most recent committer
      - last_date      : ISO date of the most recent commit (YYYY-MM-DD)
      - last_message   : subject line of the most recent commit (max 80 chars)
      - authors        : [{name, commits}] top contributors (max 3)

    Returns: dict[absolute_file_path -> git_info_dict]
    """
    try:
        # One pass: get all commits with the files they touched
        result = subprocess.run(
            [
                "git", "log",
                "--pretty=format:COMMIT|%H|%an|%ad|%s",
                "--date=short",
                "--name-only",
                "--diff-filter=d",   # exclude deleted files from listing
            ],
            cwd=repo_root,
            capture_output=True,
            text=True,
            timeout=30,
        )
        if result.returncode != 0:
            return {}
    except Exception:
        return {}

    # Parse output into per-file records
    # Format alternates: COMMIT|hash|author|date|msg  then  file1\nfile2\n...
    file_records: dict[str, dict] = {}  # rel_path -> {commits: [(hash,author,date,msg)]}

    current_meta: Optional[tuple] = None
    for line in result.stdout.splitlines():
        line = line.strip()
        if not line:
            continue
        if line.startswith("COMMIT|"):
            parts = line.split("|", 4)
            if len(parts) == 5:
                current_meta = (parts[1][:8], parts[2], parts[3], parts[4][:80])
        elif current_meta and line:
            if line not in file_records:
                file_records[line] = {"commits": []}
            file_records[line]["commits"].append(current_meta)

    # Build final per-file summary
    root_path = Path(repo_root).resolve()
    result_map: dict[str, dict] = {}

    for rel_path, data in file_records.items():
        commits = data["commits"]
        if not commits:
            continue

        # Most recent commit is first (git log default order)
        last = commits[0]

        # Count per-author commits
        author_counts: dict[str, int] = {}
        for c in commits:
            author_counts[c[1]] = author_counts.get(c[1], 0) + 1

        top_authors = sorted(author_counts.items(), key=lambda x: -x[1])[:3]

        abs_path = str((root_path / rel_path).resolve())
        result_map[abs_path] = {
            "commit_count": len(commits),
            "last_commit": last[0],
            "last_author": last[1],
            "last_date": last[2],
            "last_message": last[3],
            "top_authors": [{"name": a, "commits": c} for a, c in top_authors],
        }

    return result_map


def get_repo_stats(repo_root: str) -> dict:
    """
    High-level git stats for the whole repository.

    Returns: total_commits, branch, contributors (top 10)
    """
    stats: dict = {}

    try:
        r = subprocess.run(
            ["git", "rev-list", "--count", "HEAD"],
            cwd=repo_root, capture_output=True, text=True, timeout=5,
        )
        if r.returncode == 0:
            stats["total_commits"] = int(r.stdout.strip())
    except Exception:
        pass

    try:
        r = subprocess.run(
            ["git", "branch", "--show-current"],
            cwd=repo_root, capture_output=True, text=True, timeout=5,
        )
        if r.returncode == 0:
            stats["branch"] = r.stdout.strip()
    except Exception:
        pass

    try:
        r = subprocess.run(
            ["git", "log", "--format=%an"],
            cwd=repo_root, capture_output=True, text=True, timeout=10,
        )
        if r.returncode == 0 and r.stdout.strip():
            counts: dict[str, int] = {}
            for name in r.stdout.strip().splitlines():
                counts[name] = counts.get(name, 0) + 1
            stats["contributors"] = [
                {"name": n, "commits": c}
                for n, c in sorted(counts.items(), key=lambda x: -x[1])[:10]
            ]
    except Exception:
        pass

    return stats


def get_recent_commits(repo_root: str, limit: int = 10) -> list[dict]:
    """Return the most recent commits across the whole repo."""
    try:
        r = subprocess.run(
            ["git", "log", f"-{limit}", "--format=%H|%an|%ad|%s", "--date=short"],
            cwd=repo_root, capture_output=True, text=True, timeout=10,
        )
        commits = []
        if r.returncode == 0:
            for line in r.stdout.strip().splitlines():
                parts = line.split("|", 3)
                if len(parts) == 4:
                    commits.append({
                        "hash": parts[0][:8],
                        "author": parts[1],
                        "date": parts[2],
                        "message": parts[3][:100],
                    })
        return commits
    except Exception:
        return []
