from unittest.mock import Mock, patch

import pytest
from fastapi import HTTPException

from src.api.git_repositories import _clone_working_repository, _init_working_repository
from src.utils.git_control import create_branch


def test_clone_working_repository_uses_normal_clone() -> None:
    completed = Mock(returncode=0, stderr="")
    with patch("src.api.git_repositories.subprocess.run", return_value=completed) as run_mock:
        _clone_working_repository("git@git.commumedia.org:alice/demo.git", "/tmp/demo.git")

    run_mock.assert_called_once()
    assert run_mock.call_args.args[0] == ["git", "clone", "git@git.commumedia.org:alice/demo.git", "/tmp/demo.git"]


def test_clone_working_repository_raises_on_failure() -> None:
    completed = Mock(returncode=128, stderr="fatal: repository not found")
    with patch("src.api.git_repositories.subprocess.run", return_value=completed):
        with pytest.raises(HTTPException) as exc_info:
            _clone_working_repository("git@git.commumedia.org:alice/missing.git", "/tmp/missing.git")

    assert exc_info.value.status_code == 400
    assert "failed to clone repository" in exc_info.value.detail


def test_init_working_repository_prefers_init_b() -> None:
    init_b = Mock(returncode=0, stderr="")
    with patch("src.api.git_repositories.subprocess.run", return_value=init_b) as run_mock:
        _init_working_repository("/tmp/new-repo")

    assert run_mock.call_args.args[0] == ["git", "init", "-b", "main", "/tmp/new-repo"]


def test_init_working_repository_falls_back_to_symbolic_ref() -> None:
    init_b = Mock(returncode=1, stderr="unknown switch `b'")
    init_ok = Mock(returncode=0, stderr="")
    symbolic_ref = Mock(returncode=0, stderr="")

    with patch("src.api.git_repositories.subprocess.run", side_effect=[init_b, init_ok, symbolic_ref]) as run_mock:
        _init_working_repository("/tmp/new-repo")

    assert run_mock.call_args_list[0].args[0] == ["git", "init", "-b", "main", "/tmp/new-repo"]
    assert run_mock.call_args_list[1].args[0] == ["git", "init", "/tmp/new-repo"]
    assert run_mock.call_args_list[2].args[0] == ["git", "-C", "/tmp/new-repo", "symbolic-ref", "HEAD", "refs/heads/main"]


def test_create_branch_uses_orphan_checkout_when_head_is_unborn() -> None:
    call_count = 0

    def mock_run(repo_path: str, *args: str) -> str:
        nonlocal call_count
        call_count += 1
        if call_count == 1:
            raise RuntimeError("fatal: Needed a single revision")
        return ""

    with patch("src.utils.git_control._run_git_command", side_effect=mock_run) as run_mock:
        create_branch("/tmp/new-repo", "feature/test")

    assert run_mock.call_args_list[0].args[1:] == ("rev-parse", "--verify", "HEAD^{commit}")
    assert run_mock.call_args_list[1].args[1:] == ("checkout", "--orphan", "feature/test")
