"""Git ownership checks use real repositories: the boundary is git itself."""

from __future__ import annotations

import subprocess
from pathlib import Path

import pytest

from adw_modules import git_helper, session
from adw_modules.data_types import ConfigDefaults, ObservabilityConfig, SSSFConfig
from adw_modules.tracer import Tracer


def _git(repo: Path, *args: str) -> str:
    result = subprocess.run(["git", "-C", str(repo), *args], check=True,
                            capture_output=True, text=True)
    return result.stdout.strip()


def _repo(tmp_path: Path) -> Path:
    repo = tmp_path / "repo"
    repo.mkdir()
    _git(repo, "init", "-b", "main")
    _git(repo, "config", "user.email", "factory@test")
    _git(repo, "config", "user.name", "Factory Test")
    (repo / "tracked.txt").write_text("base\n")
    _git(repo, "add", "tracked.txt")
    _git(repo, "commit", "-m", "base")
    return repo


def test_dirty_foreign_tree_is_refused(tmp_path: Path, monkeypatch) -> None:
    repo = _repo(tmp_path)
    (repo / "owners-notes.txt").write_text("do not touch\n")
    monkeypatch.chdir(repo)

    with pytest.raises(RuntimeError, match="changes the run does not own"):
        git_helper.preflight("run123")


def test_prior_run_spec_is_factory_owned(tmp_path: Path, monkeypatch) -> None:
    repo = _repo(tmp_path)
    _git(repo, "checkout", "-b", "factory/existing-run")
    db = tmp_path / "sssf.db"
    cfg = SSSFConfig.model_validate({
        "defaults": {
            "data_dir": str(tmp_path / "data"),
            "git_branch_mode": "require_isolated",
        },
        "observability": {"db": str(db)},
        "agents": [{
            "name": "planner",
            "prompt_engineering": {"system": "unused", "user": "unused"},
            "writes": ["specs/"],
        }],
    })
    prior = Tracer(db, tmp_path / "prior-events.jsonl")
    prior.session_start("prior123", "engineer", repo=repo)
    prior.session_finish("prior123", ok=True)
    prior.conn.close()
    spec = repo / "specs" / "prior123_add-health-check.md"
    spec.parent.mkdir()
    spec.write_text("# Plan\n")
    monkeypatch.chdir(repo)

    run = session.ensure(cfg, "run123", mutates_repo=True)
    try:
        assert run.phases[-1].status == "success"
    finally:
        run.tracer.session_finish(run.adw_id, ok=True)
        run.tracer.conn.close()


def test_foreign_file_still_blocks_alongside_owned_spec(tmp_path: Path, monkeypatch) -> None:
    repo = _repo(tmp_path)
    _git(repo, "checkout", "-b", "factory/existing-run")
    spec = repo / "specs" / "prior123_add-health-check.md"
    spec.parent.mkdir()
    spec.write_text("# Plan\n")
    (repo / "owners-notes.txt").write_text("do not touch\n")
    monkeypatch.chdir(repo)

    with pytest.raises(RuntimeError) as exc_info:
        git_helper.preflight(
            "run123", spec_output_dir="specs/", known_adw_ids={"prior123"}
        )

    assert str(exc_info.value) == (
        "git preflight refused the run: target tree already has changes the run "
        "does not own (owners-notes.txt). Commit, move, or discard them, then rerun."
    )


def test_spec_with_unknown_adw_id_is_refused(tmp_path: Path, monkeypatch) -> None:
    repo = _repo(tmp_path)
    spec = repo / "specs" / "unknown123_add-health-check.md"
    spec.parent.mkdir()
    spec.write_text("# Plan\n")
    monkeypatch.chdir(repo)

    with pytest.raises(RuntimeError, match="changes the run does not own"):
        git_helper.preflight(
            "run123", spec_output_dir="specs/", known_adw_ids={"prior123"}
        )


def test_clean_tree_passes(tmp_path: Path, monkeypatch) -> None:
    repo = _repo(tmp_path)
    _git(repo, "checkout", "-b", "factory/existing-run")
    monkeypatch.chdir(repo)

    assert git_helper.preflight("run123") == "factory/existing-run"


def test_branch_creating_mode_commits_on_new_branch(tmp_path: Path, monkeypatch) -> None:
    repo = _repo(tmp_path)
    monkeypatch.chdir(repo)

    assert git_helper.preflight("run123", "create") == "factory/run123"
    (repo / "factory.txt").write_text("owned\n")
    git_helper.commit_all("factory change", ["factory.txt"])

    assert _git(repo, "branch", "--show-current") == "factory/run123"
    assert _git(repo, "log", "-1", "--format=%s") == "factory change"
    assert _git(repo, "show", "main:tracked.txt") == "base"


def test_commit_does_not_pick_up_unentitled_file(tmp_path: Path, monkeypatch) -> None:
    repo = _repo(tmp_path)
    _git(repo, "checkout", "-b", "factory/existing-run")
    monkeypatch.chdir(repo)
    git_helper.preflight("run123")

    (repo / "owned.txt").write_text("factory\n")
    (repo / "foreign.txt").write_text("owner\n")
    git_helper.commit_all("owned only", ["owned.txt"])

    assert _git(repo, "show", "--format=", "--name-only", "HEAD") == "owned.txt"
    assert _git(repo, "status", "--porcelain") == "?? foreign.txt"
