"""Integration tests for the actions layer."""

from unittest.mock import MagicMock

import pytest

from virgo.actions import GenerateArticleAction
from virgo.actions.protocols import ArticleGenerator
from virgo.agent.schemas import MarkdownArticle


class DescribeGenerateArticleActionIntegration:
    """Integration tests for GenerateArticleAction."""

    class DescribeWithMockedGenerator:
        """Tests using a mocked ArticleGenerator."""

        @pytest.fixture
        def mock_generator(self) -> MagicMock:
            """Create a mock ArticleGenerator."""
            generator = MagicMock(spec=ArticleGenerator)
            generator.generate.return_value = MarkdownArticle(
                title="Test Article",
                summary="This is a test article summary.",
                content="# Test Article\n\nThis is the content of the test article.",
                references=["https://example.com"],
            )
            return generator

        def it_should_execute_with_mocked_generator(
            self, mock_generator: MagicMock
        ) -> None:
            """Test that the action executes correctly with a mocked generator."""
            action = GenerateArticleAction(generator=mock_generator)
            result = action.execute("Test question")

            assert result is not None
            assert isinstance(result, MarkdownArticle)
            assert result.title == "Test Article"
            mock_generator.generate.assert_called_once_with("Test question")

        def it_should_return_none_when_generator_fails(
            self, mock_generator: MagicMock
        ) -> None:
            """Test that the action returns None when the generator fails."""
            mock_generator.generate.return_value = None
            action = GenerateArticleAction(generator=mock_generator)
            result = action.execute("Test question")

            assert result is None

        def it_should_pass_question_to_generator(
            self, mock_generator: MagicMock
        ) -> None:
            """Test that the question is passed correctly to the generator."""
            action = GenerateArticleAction(generator=mock_generator)
            test_question = "What are the benefits of Python?"
            action.execute(test_question)

            mock_generator.generate.assert_called_once_with(test_question)

    class DescribeProtocolCompliance:
        """Tests for protocol compliance."""

        def it_should_accept_any_article_generator_implementation(self) -> None:
            """Test that the action accepts any ArticleGenerator implementation."""

            class CustomGenerator:
                """Custom ArticleGenerator implementation."""

                def generate(self, question: str) -> MarkdownArticle | None:
                    return MarkdownArticle(
                        title="Custom Article",
                        summary="Generated by custom generator",
                        content=f"# Answer to: {question}\n\nCustom content here.",
                        references=[],
                    )

            generator = CustomGenerator()
            action = GenerateArticleAction(generator=generator)  # type: ignore[arg-type]
            result = action.execute("Test question")

            assert result is not None
            assert result.title == "Custom Article"
            assert "Test question" in result.content

        def it_should_work_with_virgo_agent(self) -> None:
            """Test that the action works with VirgoAgent as generator."""
            from virgo.agent import VirgoAgent

            # Create a mock VirgoAgent
            mock_agent = MagicMock(spec=VirgoAgent)
            mock_agent.generate.return_value = MarkdownArticle(
                title="VirgoAgent Article",
                summary="Generated by VirgoAgent",
                content="# VirgoAgent Article\n\nContent from VirgoAgent.",
                references=["https://virgo.example.com"],
            )

            action = GenerateArticleAction(generator=mock_agent)
            result = action.execute("Test with VirgoAgent")

            assert result is not None
            assert result.title == "VirgoAgent Article"
            mock_agent.generate.assert_called_once_with("Test with VirgoAgent")


class DescribeActionDependencyInjection:
    """Tests for dependency injection with actions."""

    def it_should_work_with_container(self) -> None:
        """Test that actions work correctly with the DI container."""
        from virgo.cli.container import Container

        container = Container()

        # Override the agent with a mock
        mock_agent = MagicMock()
        mock_agent.generate.return_value = MarkdownArticle(
            title="Container Test",
            summary="Testing container injection",
            content="# Container Test\n\nThis tests the DI container.",
            references=[],
        )

        with container._agent.override(mock_agent):
            action = container.generate_action()
            result = action.execute("Container test question")

            assert result is not None
            assert result.title == "Container Test"

    def it_should_provide_new_action_instance_each_time(self) -> None:
        """Test that the container provides new action instances."""
        from virgo.cli.container import Container

        container = Container()

        mock_agent = MagicMock()
        with container._agent.override(mock_agent):
            action1 = container.generate_action()
            action2 = container.generate_action()

            # Factory should create new instances
            assert action1 is not action2

    def it_should_share_agent_across_actions(self) -> None:
        """Test that the same agent instance is shared across actions."""
        from virgo.cli.container import Container

        container = Container()

        mock_agent = MagicMock()
        with container._agent.override(mock_agent):
            action1 = container.generate_action()
            action2 = container.generate_action()

            # Both actions should have the same generator (agent)
            assert action1.generator is action2.generator
