#!/usr/bin/env python3
"""unbury - exhume contributor stats from a graveyard of git repos.

Usage:
    unbury [path]           # defaults to current directory
    unbury /home/fox/git/pylons
"""

import os
import subprocess
import sys
from collections import defaultdict
from datetime import datetime, timedelta

PERIODS = [
    ("3 months", 90),
    ("1 year", 365),
    ("3 years", 365 * 3),
    ("6 years", 365 * 6),
    ("18 years", 365 * 18),
    ("lifetime", None),
]


def git_contributors(repo_path, since=None):
    """Return set of (name, email) tuples for a repo."""
    cmd = ["git", "-C", repo_path, "log", "--format=%aN\t%aE"]
    if since:
        cmd.append(f"--since={since}")
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
        contributors = set()
        for line in result.stdout.strip().split("\n"):
            if "\t" in line:
                name, email = line.split("\t", 1)
                contributors.add((name.strip(), email.strip().lower()))
        return contributors
    except (subprocess.TimeoutExpired, Exception):
        return set()


def find_repos(root):
    """Find all git repos (immediate subdirs with .git)."""
    repos = []
    for entry in sorted(os.listdir(root)):
        path = os.path.join(root, entry)
        if os.path.isdir(path) and os.path.isdir(os.path.join(path, ".git")):
            repos.append(path)
    return repos


def main():
    root = sys.argv[1] if len(sys.argv) > 1 else os.getcwd()
    root = os.path.abspath(root)

    repos = find_repos(root)
    if not repos:
        print(f"no git repos found in {root}")
        sys.exit(1)

    print(f"scanning {len(repos)} repos in {root}\n")

    now = datetime.now()

    for label, days in PERIODS:
        since = (now - timedelta(days=days)).strftime("%Y-%m-%d") if days else None
        all_contributors = set()
        repo_counts = {}

        for repo in repos:
            contribs = git_contributors(repo, since)
            if contribs:
                repo_name = os.path.basename(repo)
                repo_counts[repo_name] = len(contribs)
                all_contributors.update(contribs)

        active_repos = len(repo_counts)
        print(f"{'─' * 50}")
        print(f"{label}: {len(all_contributors)} unique contributors across {active_repos} active repos")

        if all_contributors:
            # count contributions per person across repos
            person_repos = defaultdict(list)
            for repo in repos:
                contribs = git_contributors(repo, since)
                repo_name = os.path.basename(repo)
                for c in contribs:
                    person_repos[c].append(repo_name)

            # sort by number of repos touched
            ranked = sorted(person_repos.items(), key=lambda x: -len(x[1]))
            top = ranked[:10]
            for (name, email), touched in top:
                print(f"  {name:30s} {len(touched):3d} repos  ({email})")
            if len(ranked) > 10:
                print(f"  ... and {len(ranked) - 10} more")

    print(f"{'─' * 50}")


if __name__ == "__main__":
    main()
