#!/usr/bin/env python3
"""Bulk change guard — enforces micro-commit cadence and stash safety.

Hooks:
  --check-commit   : Warns when staging >N files without a WIP checkpoint
  --check-stash-pop: Blocks `git stash pop`, suggests `apply` + `drop`

Wired into .claude/settings.json PreToolUse hooks.
"""

import argparse
import subprocess
import sys

MAX_STAGED_FILES = 8


def _git_root() -> str:
    result = subprocess.run(
        ["git", "rev-parse", "--show-toplevel"],
        capture_output=True, text=True,
    )
    return result.stdout.strip() or "."


def get_staged_file_count() -> int:
    result = subprocess.run(
        ["git", "diff", "--cached", "--name-only"],
        capture_output=True, text=True, cwd=_git_root(),
    )
    if result.returncode != 0:
        return 0
    return len([f for f in result.stdout.strip().splitlines() if f])


def has_wip_checkpoint() -> bool:
    result = subprocess.run(
        ["git", "log", "--oneline", "-20", "--grep=WIP"],
        capture_output=True, text=True, cwd=_git_root(),
    )
    return bool(result.stdout.strip())


def check_commit() -> int:
    count = get_staged_file_count()
    if count <= MAX_STAGED_FILES:
        return 0
    if has_wip_checkpoint():
        print(
            f"NOTE: Staging {count} files (>{MAX_STAGED_FILES}). "
            f"WIP checkpoint found -- proceeding.",
            file=sys.stderr,
        )
        return 0
    print(
        f"WARNING: Staging {count} files without a WIP checkpoint commit.\n"
        f"  Risk: If context compresses, uncommitted work may be lost.\n"
        f"  Options:\n"
        f"    1. Commit now (this is a warning, not a block)\n"
        f"    2. Split into smaller commits (recommended for >{MAX_STAGED_FILES} files)\n"
        f"    3. Create a WIP checkpoint: git commit -m 'WIP: batch description'",
        file=sys.stderr,
    )
    return 0  # Warning only


def check_stash_pop() -> int:
    print(
        "BLOCKED: `git stash pop` is unsafe in long sessions.\n"
        "  If context compresses after pop, you can't recover the stash.\n"
        "  Use instead:\n"
        "    git stash apply    # Restores changes, keeps stash as backup\n"
        "    # ... verify changes are correct ...\n"
        "    git stash drop     # Only after confirming apply worked",
        file=sys.stderr,
    )
    return 2  # Hard block


def main() -> int:
    parser = argparse.ArgumentParser(description="Bulk change guard")
    parser.add_argument("--check-commit", action="store_true",
                        help="Check staged file count before commit")
    parser.add_argument("--check-stash-pop", action="store_true",
                        help="Block git stash pop")
    args = parser.parse_args()

    if args.check_commit:
        return check_commit()
    if args.check_stash_pop:
        return check_stash_pop()

    parser.print_help()
    return 1


if __name__ == "__main__":
    sys.exit(main())
