"""Tests for the auto-patching init() system."""

from unittest.mock import patch, MagicMock
import sys

import agentcost
from agentcost.patch import _originals, unpatch_all


class TestInit:
    def setup_method(self):
        """Clean up global state before each test."""
        unpatch_all()
        agentcost._global_instance = None

    def teardown_method(self):
        """Clean up after each test."""
        unpatch_all()
        agentcost._global_instance = None

    def test_init_returns_agentcost_instance(self):
        ac = agentcost.init(debug=True)
        assert isinstance(ac, agentcost.AgentCost)

    def test_init_sets_global_instance(self):
        assert agentcost._global_instance is None
        ac = agentcost.init(debug=True)
        assert agentcost._global_instance is ac

    def test_init_with_api_key(self):
        ac = agentcost.init(api_key="ac_test123", debug=True)
        assert ac._api_key == "ac_test123"

    def test_init_debug_mode(self, capsys):
        agentcost.init(debug=True)
        captured = capsys.readouterr()
        # Should print something about patching (or no providers)
        assert "[agentcost]" in captured.err

    def test_shutdown_clears_global(self):
        agentcost.init(debug=True)
        assert agentcost._global_instance is not None
        agentcost.shutdown()
        assert agentcost._global_instance is None


class TestPatchOpenAI:
    def setup_method(self):
        unpatch_all()
        agentcost._global_instance = None

    def teardown_method(self):
        unpatch_all()
        agentcost._global_instance = None

    def test_patches_openai_when_installed(self):
        """Test that init() patches OpenAI if the library is importable."""
        # Create a mock openai module structure
        mock_completions_module = MagicMock()
        original_create = MagicMock()
        mock_completions_module.Completions = type(
            "Completions", (), {"create": original_create}
        )

        with patch.dict(sys.modules, {
            "openai": MagicMock(),
            "openai.resources": MagicMock(),
            "openai.resources.chat": MagicMock(),
            "openai.resources.chat.completions": mock_completions_module,
        }):
            ac = agentcost.init(debug=True, agent_id="test-agent")

            # The create method should have been replaced
            assert mock_completions_module.Completions.create is not original_create
            assert "openai" in _originals

    def test_unpatch_restores_original(self):
        """Test that unpatch_all() restores the original method."""
        mock_completions_module = MagicMock()
        original_create = MagicMock()
        mock_completions_module.Completions = type(
            "Completions", (), {"create": original_create}
        )

        with patch.dict(sys.modules, {
            "openai": MagicMock(),
            "openai.resources": MagicMock(),
            "openai.resources.chat": MagicMock(),
            "openai.resources.chat.completions": mock_completions_module,
        }):
            agentcost.init(debug=True)
            assert mock_completions_module.Completions.create is not original_create

            unpatch_all()
            assert mock_completions_module.Completions.create is original_create
            assert "openai" not in _originals


class TestPatchAnthropic:
    def setup_method(self):
        unpatch_all()
        agentcost._global_instance = None

    def teardown_method(self):
        unpatch_all()
        agentcost._global_instance = None

    def test_patches_anthropic_when_installed(self):
        """Test that init() patches Anthropic if the library is importable."""
        mock_messages_module = MagicMock()
        original_create = MagicMock()
        mock_messages_module.Messages = type(
            "Messages", (), {"create": original_create}
        )

        with patch.dict(sys.modules, {
            "anthropic": MagicMock(),
            "anthropic.resources": MagicMock(),
            "anthropic.resources.messages": mock_messages_module,
        }):
            ac = agentcost.init(debug=True, agent_id="test-agent")

            assert mock_messages_module.Messages.create is not original_create
            assert "anthropic" in _originals

    def test_unpatch_restores_original(self):
        mock_messages_module = MagicMock()
        original_create = MagicMock()
        mock_messages_module.Messages = type(
            "Messages", (), {"create": original_create}
        )

        with patch.dict(sys.modules, {
            "anthropic": MagicMock(),
            "anthropic.resources": MagicMock(),
            "anthropic.resources.messages": mock_messages_module,
        }):
            agentcost.init(debug=True)
            assert mock_messages_module.Messages.create is not original_create

            unpatch_all()
            assert mock_messages_module.Messages.create is original_create


class TestNoProviders:
    def setup_method(self):
        unpatch_all()
        agentcost._global_instance = None

    def teardown_method(self):
        unpatch_all()
        agentcost._global_instance = None

    def test_init_works_without_providers(self, capsys):
        """init() should work even if no LLM libraries are installed."""
        ac = agentcost.init(debug=True)
        assert ac is not None
        captured = capsys.readouterr()
        assert "[agentcost]" in captured.err

    def test_double_init_is_safe(self):
        """Calling init() twice shouldn't break anything."""
        ac1 = agentcost.init(debug=True)
        ac2 = agentcost.init(debug=True)
        assert ac2 is not ac1  # New instance each time
        assert agentcost._global_instance is ac2
