"""Unit tests for `attractor.testing.create_test_repo`. See SPEC.md §12.1.

The helper is exercised transitively by every engine / worktree / cli
test (via the migrated `seeded_repo` and `dod_repo` fixtures), but a
direct unit pins its observable contract: where it puts the repo, what
config it writes, what the seed commit looks like.
"""

# [unit->REQ-API-TESTING-HELPERS]

from __future__ import annotations

import subprocess
from pathlib import Path

import pygit2
import pytest

from attractor.testing import create_test_repo


def test_creates_non_bare_repo_at_path(tmp_path: Path) -> None:
    """Returns the same path; `.git` exists; repo is non-bare."""
    target = tmp_path / "repo"
    result = create_test_repo(target)

    assert result == target
    assert target.is_dir()
    assert (target / ".git").exists()

    repo = pygit2.Repository(str(target))
    assert repo.workdir is not None  # non-bare


def test_signing_disabled_in_local_config(tmp_path: Path) -> None:
    """commit.gpgsign and tag.gpgsign are forced to false locally.

    Critical so hosts with `commit.gpgsign=true` in their global
    gitconfig don't break test runs when their signing key is missing
    (CI, sandboxes, fresh dev VMs).
    """
    repo_path = create_test_repo(tmp_path / "repo")
    repo = pygit2.Repository(str(repo_path))

    assert repo.config["commit.gpgsign"] == "false"
    assert repo.config["tag.gpgsign"] == "false"


def test_seed_commit_on_main_with_gitignore(tmp_path: Path) -> None:
    """HEAD points at main; one commit; the tree has a `.gitignore` blob."""
    repo_path = create_test_repo(tmp_path / "repo")
    repo = pygit2.Repository(str(repo_path))

    # HEAD resolves to main
    assert not repo.head_is_unborn
    assert repo.head.shorthand == "main"

    # Exactly one commit, with no parents
    head_commit = repo.head.peel(pygit2.Commit)
    assert isinstance(head_commit, pygit2.Commit)
    assert len(head_commit.parents) == 0

    # Tree contains a `.gitignore`
    tree = head_commit.tree
    assert ".gitignore" in [entry.name for entry in tree]


def test_git_cli_agrees_with_pygit2(tmp_path: Path) -> None:
    """The git CLI can rev-parse the seeded HEAD — guards pygit2/git drift."""
    repo_path = create_test_repo(tmp_path / "repo")
    result = subprocess.run(
        ["git", "-C", str(repo_path), "rev-parse", "HEAD"],
        capture_output=True,
        check=True,
        text=True,
    )
    sha = result.stdout.strip()
    assert len(sha) == 40  # full SHA-1


def test_alternate_initial_branch(tmp_path: Path) -> None:
    """initial_branch overrides the default `main`."""
    repo_path = create_test_repo(tmp_path / "repo", initial_branch="trunk")
    repo = pygit2.Repository(str(repo_path))
    assert repo.head.shorthand == "trunk"


def test_refuses_existing_path(tmp_path: Path) -> None:
    """Pre-existing directory raises — tests want fresh state per call."""
    target = tmp_path / "repo"
    target.mkdir()
    with pytest.raises(FileExistsError):
        create_test_repo(target)


def test_not_re_exported_from_top_level() -> None:
    """attractor.testing is NOT part of the stable host API contract.

    This pins the policy split: the host API surface is
    `attractor.__all__`; test scaffolding is a separate submodule.
    Promoting `create_test_repo` into `attractor.__all__` is a contract
    change, not an accident.
    """
    import attractor

    assert "create_test_repo" not in attractor.__all__
