"""Tests for ievo.core.github_auth — GitHub CLI detection + PAT fallback."""

from __future__ import annotations

from pathlib import Path
from unittest.mock import patch

from ievo.core.credentials import ensure_keys
from ievo.core.github_auth import check_gh_auth, check_gh_cli


def test_check_gh_cli_found() -> None:
    with patch("ievo.core.github_auth.shutil.which", return_value="/usr/bin/gh"):
        assert check_gh_cli() is True


def test_check_gh_cli_not_found() -> None:
    with patch("ievo.core.github_auth.shutil.which", return_value=None):
        assert check_gh_cli() is False


def test_check_gh_auth_authenticated() -> None:
    mock_result = type(
        "Result", (), {"returncode": 0, "stderr": "Logged in to github.com account denis (token)\n"}
    )()
    with (
        patch("ievo.core.github_auth.check_gh_cli", return_value=True),
        patch("ievo.core.github_auth.subprocess.run", return_value=mock_result),
    ):
        assert check_gh_auth() == "denis"


def test_check_gh_auth_not_authenticated() -> None:
    mock_result = type("Result", (), {"returncode": 1, "stderr": ""})()
    with (
        patch("ievo.core.github_auth.check_gh_cli", return_value=True),
        patch("ievo.core.github_auth.subprocess.run", return_value=mock_result),
    ):
        assert check_gh_auth() is None


def test_check_gh_auth_no_cli() -> None:
    with patch("ievo.core.github_auth.check_gh_cli", return_value=False):
        assert check_gh_auth() is None


def test_check_gh_auth_account_at_end() -> None:
    """When 'account' is the last word, no username extracted → returns 'unknown'."""
    mock_result = type(
        "Result", (), {"returncode": 0, "stderr": "Logged in to github.com account\n"}
    )()
    with (
        patch("ievo.core.github_auth.check_gh_cli", return_value=True),
        patch("ievo.core.github_auth.subprocess.run", return_value=mock_result),
    ):
        assert check_gh_auth() == "unknown"


def test_prompt_github_auth_gh_cli_already_authed(tmp_path: Path) -> None:
    """When gh CLI is authed, should return 'gh_cli' without prompting."""
    from ievo.core.github_auth import prompt_github_auth
    from ievo.core.global_config import load_global_config

    ensure_keys(tmp_path)
    load_global_config(tmp_path)

    with (
        patch("ievo.core.github_auth.check_gh_cli", return_value=True),
        patch("ievo.core.github_auth.check_gh_auth", return_value="denis"),
    ):
        result = prompt_github_auth(tmp_path)
        assert result == "gh_cli"

    from ievo.core.global_config import get_config

    assert get_config(tmp_path, "github_auth") == "gh_cli"


def test_prompt_github_auth_pat_fallback(tmp_path: Path) -> None:
    """When no gh CLI, user enters PAT token."""
    from ievo.core.github_auth import prompt_github_auth
    from ievo.core.global_config import load_global_config

    ensure_keys(tmp_path)
    load_global_config(tmp_path)

    with (
        patch("ievo.core.github_auth.check_gh_cli", return_value=False),
        patch("builtins.input", return_value="ghp_test123"),
    ):
        result = prompt_github_auth(tmp_path)
        assert result == "pat"

    from ievo.core.credentials import get_credential
    from ievo.core.global_config import get_config

    assert get_config(tmp_path, "github_auth") == "pat"
    assert get_credential(tmp_path, "GITHUB_TOKEN") == "ghp_test123"


def test_prompt_github_auth_skipped(tmp_path: Path) -> None:
    """When no gh CLI and user presses Enter, should return None."""
    from ievo.core.github_auth import prompt_github_auth
    from ievo.core.global_config import load_global_config

    ensure_keys(tmp_path)
    load_global_config(tmp_path)

    with (
        patch("ievo.core.github_auth.check_gh_cli", return_value=False),
        patch("builtins.input", return_value=""),
    ):
        result = prompt_github_auth(tmp_path)
        assert result is None


def test_check_gh_auth_file_not_found() -> None:
    """FileNotFoundError during subprocess.run should return None."""
    with (
        patch("ievo.core.github_auth.check_gh_cli", return_value=True),
        patch("ievo.core.github_auth.subprocess.run", side_effect=FileNotFoundError),
    ):
        assert check_gh_auth() is None


def test_check_gh_auth_no_account_line() -> None:
    """When output has no 'account' word, return 'unknown'."""
    mock_result = type("Result", (), {"returncode": 0, "stderr": "Logged in to github.com\n"})()
    with (
        patch("ievo.core.github_auth.check_gh_cli", return_value=True),
        patch("ievo.core.github_auth.subprocess.run", return_value=mock_result),
    ):
        assert check_gh_auth() == "unknown"


def test_prompt_github_auth_gh_not_authed_then_login_succeeds(tmp_path: Path) -> None:
    """gh CLI installed but not authed, user runs gh auth login, succeeds."""
    from ievo.core.github_auth import prompt_github_auth
    from ievo.core.global_config import load_global_config

    ensure_keys(tmp_path)
    load_global_config(tmp_path)

    with (
        patch("ievo.core.github_auth.check_gh_cli", return_value=True),
        patch("ievo.core.github_auth.check_gh_auth", side_effect=[None, "denis"]),
        patch("builtins.input", return_value="y"),
        patch("ievo.core.github_auth.subprocess.run"),
    ):
        result = prompt_github_auth(tmp_path)
        assert result == "gh_cli"


def test_prompt_github_auth_gh_not_authed_login_fails(tmp_path: Path) -> None:
    """gh CLI installed but login fails, falls through to PAT."""
    from ievo.core.github_auth import prompt_github_auth
    from ievo.core.global_config import load_global_config

    ensure_keys(tmp_path)
    load_global_config(tmp_path)

    with (
        patch("ievo.core.github_auth.check_gh_cli", return_value=True),
        patch("ievo.core.github_auth.check_gh_auth", return_value=None),
        patch("builtins.input", side_effect=["y", "ghp_test_pat"]),
        patch("ievo.core.github_auth.subprocess.run"),
    ):
        result = prompt_github_auth(tmp_path)
        assert result == "pat"


def test_prompt_github_auth_gh_not_authed_login_file_error(tmp_path: Path) -> None:
    """gh auth login raises FileNotFoundError, falls through to PAT."""
    from ievo.core.github_auth import prompt_github_auth
    from ievo.core.global_config import load_global_config

    ensure_keys(tmp_path)
    load_global_config(tmp_path)

    with (
        patch("ievo.core.github_auth.check_gh_cli", return_value=True),
        patch("ievo.core.github_auth.check_gh_auth", return_value=None),
        patch("builtins.input", side_effect=["y", "ghp_test_pat"]),
        patch("ievo.core.github_auth.subprocess.run", side_effect=FileNotFoundError),
    ):
        result = prompt_github_auth(tmp_path)
        assert result == "pat"


def test_prompt_github_auth_gh_not_authed_decline_login(tmp_path: Path) -> None:
    """gh CLI installed, user declines login, enters PAT."""
    from ievo.core.github_auth import prompt_github_auth
    from ievo.core.global_config import load_global_config

    ensure_keys(tmp_path)
    load_global_config(tmp_path)

    with (
        patch("ievo.core.github_auth.check_gh_cli", return_value=True),
        patch("ievo.core.github_auth.check_gh_auth", return_value=None),
        patch("builtins.input", side_effect=["n", "ghp_test_pat"]),
    ):
        result = prompt_github_auth(tmp_path)
        assert result == "pat"


def test_get_github_token_gh_cli(tmp_path: Path) -> None:
    """get_github_token returns token from gh CLI."""
    from ievo.core.github_auth import get_github_token
    from ievo.core.global_config import load_global_config, set_config

    load_global_config(tmp_path)
    set_config(tmp_path, "github_auth", "gh_cli")

    mock_result = type("Result", (), {"stdout": "ghp_from_cli\n"})()
    with patch("ievo.core.github_auth.subprocess.run", return_value=mock_result):
        assert get_github_token(tmp_path) == "ghp_from_cli"


def test_get_github_token_gh_cli_error(tmp_path: Path) -> None:
    """get_github_token returns None when gh auth token fails."""
    from ievo.core.github_auth import get_github_token
    from ievo.core.global_config import load_global_config, set_config

    load_global_config(tmp_path)
    set_config(tmp_path, "github_auth", "gh_cli")

    with patch("ievo.core.github_auth.subprocess.run", side_effect=FileNotFoundError):
        assert get_github_token(tmp_path) is None


def test_get_github_token_pat(tmp_path: Path) -> None:
    """get_github_token returns token from encrypted credentials."""
    from ievo.core.github_auth import get_github_token
    from ievo.core.global_config import load_global_config, set_config

    ensure_keys(tmp_path)
    load_global_config(tmp_path)
    set_config(tmp_path, "github_auth", "pat")

    from ievo.core.credentials import set_credential

    set_credential(tmp_path, "GITHUB_TOKEN", "ghp_encrypted")

    assert get_github_token(tmp_path) == "ghp_encrypted"


def test_get_github_token_no_method(tmp_path: Path) -> None:
    """get_github_token returns None when no auth method configured."""
    from ievo.core.github_auth import get_github_token
    from ievo.core.global_config import load_global_config

    load_global_config(tmp_path)

    assert get_github_token(tmp_path) is None
