#!/usr/bin/env python3
"""Original Git 101 lab: real local Git operations in a disposable repository.

Requires Python 3.11+ and Git 2.28+. No remote, model, credentials or network.
Only the new temporary directory is written; it is removed after capture.
"""
import json
import os
from pathlib import Path
import shutil
import subprocess
import tempfile

# Make separate copies for the two workbook experiments.
RESTAGE_AFTER_EDIT = False
INCLUDE_NOTE = False


def run_lab():
    executable = shutil.which("git")
    if executable is None:
        raise RuntimeError("Git is missing. Use an approved Git 2.28+ installation.")
    with tempfile.TemporaryDirectory(prefix="fde-git-101-") as temporary:
        root = Path(temporary)
        repository = root / "repository"
        repository.mkdir()
        empty_template = root / "empty-template"
        empty_template.mkdir()
        empty_config = root / "empty-config"
        empty_config.write_text("", encoding="utf-8")
        # Do not inherit a surrounding repository, index, config injection or identity.
        environment = {key: value for key, value in os.environ.items() if not key.startswith("GIT_")}
        environment.update(GIT_CONFIG_NOSYSTEM="1", GIT_CONFIG_GLOBAL=str(empty_config),
                           GIT_TERMINAL_PROMPT="0", LC_ALL="C")
        transcript = []

        def git(*arguments):
            result = subprocess.run(
                [executable, "-c", "user.name=FDE Training Fixture",
                 "-c", "user.email=learner@example.invalid", "-c", "commit.gpgsign=false",
                 "-c", "core.autocrlf=false", *arguments],
                cwd=repository, env=environment, shell=False, capture_output=True,
                text=True, encoding="utf-8", timeout=10, check=True,
            )
            return result.stdout

        def write_limit(value):
            (repository / "policy.json").write_text(
                json.dumps({"max_items": value}, indent=2) + "\n", encoding="utf-8")

        def snapshot(event):
            working = json.loads((repository / "policy.json").read_text())
            staged = json.loads(git("show", ":policy.json"))
            committed = json.loads(git("show", "HEAD:policy.json"))
            return {
                "event": event, "working": working, "index": staged, "committed": committed,
                "status": git("status", "--porcelain=v1", "--untracked-files=all").splitlines(),
                "unstaged_diff": git("diff", "--no-ext-diff", "--no-textconv", "--", "policy.json"),
                "staged_diff": git("diff", "--cached", "--no-ext-diff", "--no-textconv", "--", "policy.json"),
                "branch": git("symbolic-ref", "--short", "HEAD").strip(),
                "commit": git("rev-parse", "HEAD").strip(),
            }

        git("init", "-q", "-b", "main", f"--template={empty_template}")
        write_limit(1)
        git("add", "--", "policy.json")
        git("commit", "-q", "-m", "Baseline: one item")
        baseline = git("rev-parse", "HEAD").strip()
        transcript.append("git init -b main; git add -- policy.json; git commit -m <baseline>")
        events = [snapshot("baseline")]

        write_limit(2)
        (repository / "note.txt").write_text("An unrelated fictional planning note.\n", encoding="utf-8")
        events.append(snapshot("edited"))
        git("add", "--", "policy.json")
        transcript.append("git add -- policy.json")
        events.append(snapshot("staged"))

        write_limit(3)
        events.append(snapshot("edited-after-stage"))
        if RESTAGE_AFTER_EDIT:
            git("add", "--", "policy.json")
            transcript.append("git add -- policy.json (workbook experiment)")
        if INCLUDE_NOTE:
            git("add", "--", "note.txt")
            transcript.append("git add -- note.txt (workbook experiment)")
        events.append(snapshot("review"))

        # Plain commit uses the index; no -a or path argument silently changes that scope.
        git("commit", "-q", "-m", "Record the selected policy snapshot")
        transcript.append("git commit -m <selected snapshot>")
        committed = snapshot("committed")
        committed["tree_files"] = git("ls-tree", "--name-only", "HEAD").splitlines()
        committed["fixture_check"] = {
            "claim": "max_items equals 3; this is one value check, not an application test suite",
            "working_passes": committed["working"]["max_items"] == 3,
            "committed_passes": committed["committed"]["max_items"] == 3,
        }
        events.append(committed)

        git("branch", "review/baseline", baseline)
        transcript.append("git branch review/baseline <baseline commit>")
        branch = snapshot("branch-reference")
        branch["baseline_branch_commit"] = git("rev-parse", "review/baseline").strip()
        branch["baseline_branch_policy"] = json.loads(git("show", "review/baseline:policy.json"))
        branch["remotes"] = git("remote").splitlines()
        events.append(branch)
        report = {"scope": "Disposable local Git repository; no remote, network or application execution",
                  "experiments": {"restage": RESTAGE_AFTER_EDIT, "include_note": INCLUDE_NOTE},
                  "commands": transcript, "events": events}
    report["temporary_repository_removed"] = not root.exists()
    return report


if __name__ == "__main__":
    print(json.dumps(run_lab(), indent=2))
