import unittest
from unittest.mock import patch

import git

from codeflash_core._git import (
    check_and_push_branch,
    check_running_in_git_repo,
    get_repo_owner_and_name,
)


class TestGitUtils(unittest.TestCase):
    @patch("codeflash_core._git.get_remote_url")
    def test_test_get_repo_owner_and_name(self, mock_get_remote_url):
        # Test with a standard GitHub HTTPS URL
        mock_get_remote_url.return_value = "https://github.com/owner/repo.git"
        get_repo_owner_and_name.cache_clear()
        owner, repo_name = get_repo_owner_and_name()
        assert owner == "owner"
        assert repo_name == "repo"

        # Test with a GitHub SSH URL
        mock_get_remote_url.return_value = "git@github.com:owner/repo.git"
        get_repo_owner_and_name.cache_clear()
        owner, repo_name = get_repo_owner_and_name()
        assert owner == "owner"
        assert repo_name == "repo"

        # Test with another GitHub SSH URL
        mock_get_remote_url.return_value = (
            "git@github.com:codeflash-ai/posthog.git"
        )
        get_repo_owner_and_name.cache_clear()
        owner, repo_name = get_repo_owner_and_name()
        assert owner == "codeflash-ai"
        assert repo_name == "posthog"

        # Test with a URL without the .git suffix
        mock_get_remote_url.return_value = "https://github.com/owner/repo"
        get_repo_owner_and_name.cache_clear()
        owner, repo_name = get_repo_owner_and_name()
        assert owner == "owner"
        assert repo_name == "repo"

        # Test with another GitHub SSH URL
        mock_get_remote_url.return_value = (
            "git@github.com:codeflash-ai/posthog/"
        )
        get_repo_owner_and_name.cache_clear()
        owner, repo_name = get_repo_owner_and_name()
        assert owner == "codeflash-ai"
        assert repo_name == "posthog"

    @patch("codeflash_core._git.git.Repo")
    def test_check_running_in_git_repo_in_git_repo(self, mock_repo):
        mock_repo.return_value.git_dir = "/path/to/repo/.git"
        assert check_running_in_git_repo("/path/to/repo")

    @patch("codeflash_core._git.git.Repo")
    def test_check_running_in_git_repo_not_in_git_repo(self, mock_repo):
        mock_repo.side_effect = git.InvalidGitRepositoryError  # type: ignore
        assert check_running_in_git_repo("/path/to/non-repo") == False

    @patch("codeflash_core._git.git.Repo")
    @patch(
        "codeflash_core._git.sys.__stdin__.isatty",
        return_value=False,
    )
    def test_check_running_in_git_repo_not_in_git_repo_non_interactive(
        self, mock_isatty, mock_repo
    ):
        mock_repo.side_effect = git.exc.InvalidGitRepositoryError  # type: ignore
        assert check_running_in_git_repo("/path/to/non-repo") is False

    @patch("codeflash_core._git.git.Repo")
    @patch(
        "codeflash_core._git.sys.__stdin__.isatty",
        return_value=True,
    )
    def test_check_and_push_branch(self, mock_isatty, mock_repo):
        mock_repo_instance = mock_repo.return_value
        # Mock HEAD not being detached
        mock_repo_instance.head.is_detached = False
        mock_repo_instance.active_branch.name = "test-branch"
        mock_repo_instance.refs = []

        mock_origin = mock_repo_instance.remote.return_value
        mock_origin.push.return_value = None

        # Previously used rich.prompt.Confirm.ask; now uses confirm_fn callback
        assert check_and_push_branch(
            mock_repo_instance, confirm_fn=lambda msg: True
        )
        mock_origin.push.assert_called_once_with(
            mock_repo_instance.active_branch
        )
        mock_origin.push.reset_mock()

        # Test when branch is already pushed
        mock_repo_instance.refs = [
            f"origin/{mock_repo_instance.active_branch.name}"
        ]
        assert check_and_push_branch(mock_repo_instance)
        mock_origin.push.assert_not_called()
        mock_origin.push.reset_mock()

    @patch("codeflash_core._git.git.Repo")
    @patch(
        "codeflash_core._git.sys.__stdin__.isatty",
        return_value=False,
    )
    def test_check_and_push_branch_non_tty(self, mock_isatty, mock_repo):
        mock_repo_instance = mock_repo.return_value
        # Mock HEAD not being detached
        mock_repo_instance.head.is_detached = False
        mock_repo_instance.active_branch.name = "test-branch"
        mock_repo_instance.refs = []

        mock_origin = mock_repo_instance.remote.return_value
        mock_origin.push.return_value = None

        assert not check_and_push_branch(mock_repo_instance)
        mock_origin.push.assert_not_called()
        mock_origin.push.reset_mock()

    @patch("codeflash_core._git.git.Repo")
    def test_check_and_push_branch_detached_head(self, mock_repo):
        mock_repo_instance = mock_repo.return_value
        # Mock HEAD being detached
        mock_repo_instance.head.is_detached = True

        mock_origin = mock_repo_instance.remote.return_value
        mock_origin.push.return_value = None

        # Should return False when HEAD is detached
        assert not check_and_push_branch(mock_repo_instance)
        mock_origin.push.assert_not_called()


if __name__ == "__main__":
    unittest.main()
