#!/usr/bin/env python3
"""Check committed or staged prose without reading unstaged working-tree edits.

Requires Git, Python 3, and the complete Zero Slop package. No network calls.
Exit codes: 0 passed/no prose changes, 1 review required, 2 execution error.
"""
import argparse
import json
import math
import os
from pathlib import Path
import subprocess
import sys


def git(*args):
    return subprocess.run(
        ["git", *args], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
        check=True, timeout=15,
    ).stdout


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    mode = parser.add_mutually_exclusive_group(required=True)
    mode.add_argument("--staged", action="store_true", help="check index contents")
    mode.add_argument("--base", help="compare merge base with committed HEAD")
    parser.add_argument("--scorer", required=True, type=Path, help="full package's scripts/slopscore.py")
    parser.add_argument("--gate", type=float, default=25)
    args = parser.parse_args()
    scorer = args.scorer.resolve()
    if not scorer.is_file() or not math.isfinite(args.gate) or not 0 <= args.gate <= 100:
        parser.error("provide an existing scorer and a finite gate from 0 to 100")
    # Resolve the package before changing directories. Git paths are root-relative.
    os.chdir(os.fsdecode(git("rev-parse", "--show-toplevel").rstrip(b"\n")))
    diff = ["diff", "--name-only", "-z", "--no-renames", "--diff-filter=ACM"]
    if args.staged:
        diff += ["--cached"]
        revision = ""
    else:
        base = git("rev-parse", "--verify", "--end-of-options", args.base + "^{commit}").decode().strip()
        ancestor = git("merge-base", base, "HEAD").decode().strip()
        diff += [ancestor, "HEAD"]
        revision = "HEAD"
    names = git(*diff, "--").split(b"\0")
    status = 0
    for raw in names:
        if not raw or Path(os.fsdecode(raw)).suffix.lower() not in {".md", ".markdown", ".mdx", ".txt"}:
            continue
        name = os.fsdecode(raw)
        content = git("show", revision + ":" + name)
        print("Checking " + json.dumps(name), flush=True)
        result = subprocess.run(
            [sys.executable, str(scorer), "--json", "--gate", str(args.gate), "-"],
            input=content, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=30,
        )
        sys.stdout.buffer.write(result.stdout)
        sys.stdout.buffer.flush()
        sys.stderr.buffer.write(result.stderr)
        # An execution error must never become a successful check.
        if result.returncode not in (0, 1):
            status = 2
        else:
            try:
                report = json.loads(result.stdout)
                if not isinstance(report.get("ai_likelihood"), (int, float)):
                    raise ValueError("missing score")
            except (ValueError, AttributeError):
                status = 2
            else:
                status = max(status, result.returncode)
    return status


if __name__ == "__main__":
    try:
        sys.exit(main())
    except (OSError, subprocess.SubprocessError) as error:
        print("Could not complete the prose check: " + str(error), file=sys.stderr)
        sys.exit(2)
