from __future__ import annotations

import os
import subprocess
from pathlib import Path

import pytest

from project_hub.git.ops import (
    GitVersionError,
    check_git_version,
    fetch_one,
    git_status,
    pull_safe_one,
)
from project_hub.core.models import PullStatus


# ---------------------------------------------------------------------------
# Sync tests
# ---------------------------------------------------------------------------

def test_check_git_version_ok():
    """check_git_version() should not raise on modern systems."""
    check_git_version()  # minimum=(2,38) — any recent git should pass


def test_git_status_clean_repo(tmp_workspace: Path):
    repo = tmp_workspace / "repo-alpha"
    status = git_status(repo)
    assert status.branch is not None
    assert status.dirty is False


def test_git_status_dirty_repo(tmp_workspace: Path):
    repo = tmp_workspace / "repo-alpha"
    (repo / "README.md").write_text("modified")
    status = git_status(repo)
    assert status.dirty is True


def test_git_status_untracked_not_dirty(tmp_workspace: Path):
    repo = tmp_workspace / "repo-alpha"
    (repo / "untracked.txt").write_text("new file")
    status = git_status(repo)
    assert status.dirty is False


def test_git_status_no_upstream(tmp_workspace: Path):
    """With no upstream configured, ahead and behind should both be 0."""
    repo = tmp_workspace / "repo-alpha"
    status = git_status(repo)
    assert status.ahead == 0
    assert status.behind == 0


# ---------------------------------------------------------------------------
# Async tests
# ---------------------------------------------------------------------------

@pytest.mark.asyncio
async def test_fetch_one_no_remote(tmp_workspace: Path):
    """fetch on a repo with an unreachable remote returns a RepoResult with repo name."""
    repo = tmp_workspace / "repo-alpha"
    result = await fetch_one(repo)
    assert result.repo == "repo-alpha"
    # Remote is unreachable, git fetch --all fails
    assert result.status == "error"
    assert result.message  # should contain the git error message


@pytest.mark.asyncio
async def test_pull_safe_dirty_repo(tmp_workspace: Path):
    """pull_safe returns SKIPPED_DIRTY when repo has uncommitted changes."""
    repo = tmp_workspace / "repo-alpha"
    (repo / "README.md").write_text("modified")
    result = await pull_safe_one(repo)
    assert result.status == PullStatus.SKIPPED_DIRTY


@pytest.mark.asyncio
async def test_pull_safe_no_upstream(tmp_workspace: Path):
    """pull_safe returns ALREADY_UP_TO_DATE or ERROR when no upstream is configured."""
    repo = tmp_workspace / "repo-alpha"
    result = await pull_safe_one(repo)
    # No upstream tracking branch -> ahead=0, behind=0 -> already up to date
    assert result.status == PullStatus.ALREADY_UP_TO_DATE
