"""Tests for git operations."""

import subprocess
from pathlib import Path

from legionnaire.git_ops import (
    branch_delete,
    branch_exists,
    current_branch,
    current_head,
    current_upstream,
    ensure_worktree_add,
    is_worktree_dirty,
    list_branches_with_prefix,
    rev_parse,
    worktree_list_porcelain,
    worktree_remove,
)


class TestCurrentHead:
    """Tests for current_head function."""

    def test_returns_sha(self, git_repo: Path):
        sha = current_head(git_repo)
        assert len(sha) == 40
        assert all(c in "0123456789abcdef" for c in sha)


class TestCurrentBranch:
    """Tests for current_branch function."""

    def test_returns_branch_name(self, git_repo: Path):
        branch = current_branch(git_repo)
        # Default branch could be main or master depending on git config
        assert branch in ("main", "master")

    def test_returns_none_when_detached(self, git_repo: Path):
        # Detach HEAD
        sha = current_head(git_repo)
        subprocess.run(["git", "checkout", sha], cwd=git_repo, check=True, capture_output=True)

        branch = current_branch(git_repo)
        assert branch is None


class TestCurrentUpstream:
    """Tests for current_upstream function."""

    def test_returns_none_when_no_upstream(self, git_repo: Path):
        upstream = current_upstream(git_repo)
        assert upstream is None


class TestRevParse:
    """Tests for rev_parse function."""

    def test_resolves_head(self, git_repo: Path):
        sha = rev_parse(git_repo, "HEAD")
        assert len(sha) == 40

    def test_resolves_branch(self, git_repo: Path):
        branch = current_branch(git_repo)
        sha = rev_parse(git_repo, branch)
        assert len(sha) == 40


class TestBranchExists:
    """Tests for branch_exists function."""

    def test_existing_branch(self, git_repo: Path):
        branch = current_branch(git_repo)
        assert branch_exists(git_repo, branch) is True

    def test_nonexistent_branch(self, git_repo: Path):
        assert branch_exists(git_repo, "nonexistent-branch") is False


class TestWorktreeListPorcelain:
    """Tests for worktree_list_porcelain function."""

    def test_lists_main_worktree(self, git_repo: Path):
        worktrees = worktree_list_porcelain(git_repo)
        assert len(worktrees) == 1
        assert worktrees[0].path == git_repo
        assert worktrees[0].branch in ("main", "master")

    def test_lists_added_worktree(self, git_repo: Path, tmp_path: Path):
        worktree_path = tmp_path / "worktree"
        subprocess.run(
            ["git", "worktree", "add", "-b", "test-branch", str(worktree_path)],
            cwd=git_repo,
            check=True,
            capture_output=True,
        )

        worktrees = worktree_list_porcelain(git_repo)
        assert len(worktrees) == 2

        wt_paths = [w.path for w in worktrees]
        assert worktree_path in wt_paths


class TestEnsureWorktreeAdd:
    """Tests for ensure_worktree_add function."""

    def test_creates_new_worktree(self, git_repo: Path, tmp_path: Path):
        worktree_path = tmp_path / "new_worktree"

        created = ensure_worktree_add(git_repo, worktree_path, "new-branch", "HEAD")

        assert created is True
        assert worktree_path.exists()
        assert branch_exists(git_repo, "new-branch")

    def test_idempotent_on_existing_worktree(self, git_repo: Path, tmp_path: Path):
        worktree_path = tmp_path / "existing_worktree"

        ensure_worktree_add(git_repo, worktree_path, "existing-branch", "HEAD")
        created = ensure_worktree_add(git_repo, worktree_path, "existing-branch", "HEAD")

        assert created is False

    def test_uses_existing_branch(self, git_repo: Path, tmp_path: Path):
        # Create branch first
        subprocess.run(
            ["git", "branch", "pre-existing"],
            cwd=git_repo,
            check=True,
            capture_output=True,
        )

        worktree_path = tmp_path / "worktree_for_existing"
        created = ensure_worktree_add(git_repo, worktree_path, "pre-existing", "HEAD")

        assert created is True
        assert worktree_path.exists()


class TestWorktreeRemove:
    """Tests for worktree_remove function."""

    def test_removes_worktree(self, git_repo: Path, tmp_path: Path):
        worktree_path = tmp_path / "to_remove"
        ensure_worktree_add(git_repo, worktree_path, "remove-branch", "HEAD")
        assert worktree_path.exists()

        worktree_remove(git_repo, worktree_path)

        worktrees = worktree_list_porcelain(git_repo)
        wt_paths = [w.path for w in worktrees]
        assert worktree_path not in wt_paths


class TestBranchDelete:
    """Tests for branch_delete function."""

    def test_deletes_branch(self, git_repo: Path, tmp_path: Path):
        # Create and remove a worktree to free the branch
        worktree_path = tmp_path / "temp_wt"
        ensure_worktree_add(git_repo, worktree_path, "delete-me", "HEAD")
        worktree_remove(git_repo, worktree_path)

        assert branch_exists(git_repo, "delete-me")
        branch_delete(git_repo, "delete-me")
        assert not branch_exists(git_repo, "delete-me")


class TestIsWorktreeDirty:
    """Tests for is_worktree_dirty function."""

    def test_clean_worktree(self, git_repo: Path):
        assert is_worktree_dirty(git_repo) is False

    def test_dirty_worktree_untracked(self, git_repo: Path):
        (git_repo / "new_file.txt").write_text("content")
        assert is_worktree_dirty(git_repo) is True

    def test_dirty_worktree_modified(self, git_repo: Path):
        (git_repo / "README.md").write_text("modified content")
        assert is_worktree_dirty(git_repo) is True


class TestListBranchesWithPrefix:
    """Tests for list_branches_with_prefix function."""

    def test_finds_matching_branches(self, git_repo: Path):
        subprocess.run(
            ["git", "branch", "feature/one"],
            cwd=git_repo,
            check=True,
            capture_output=True,
        )
        subprocess.run(
            ["git", "branch", "feature/two"],
            cwd=git_repo,
            check=True,
            capture_output=True,
        )
        subprocess.run(
            ["git", "branch", "other-branch"],
            cwd=git_repo,
            check=True,
            capture_output=True,
        )

        branches = list_branches_with_prefix(git_repo, "feature/")
        assert sorted(branches) == ["feature/one", "feature/two"]

    def test_returns_empty_for_no_matches(self, git_repo: Path):
        branches = list_branches_with_prefix(git_repo, "nonexistent/")
        assert branches == []
