"""
Comprehensive tests for CardFactory class.
Tests card creation, loading, type registration, and storage operations.
"""

import pytest
from unittest.mock import Mock, patch
import uuid


class TestCardFactoryTypeRegistry:
    """Tests for card type registry."""

    def test_has_news_type(self):
        """Test has 'news' type registered."""
        from local_deep_research.news.core.card_factory import CardFactory

        assert "news" in CardFactory._card_types

    def test_has_research_type(self):
        """Test has 'research' type registered."""
        from local_deep_research.news.core.card_factory import CardFactory

        assert "research" in CardFactory._card_types

    def test_has_update_type(self):
        """Test has 'update' type registered."""
        from local_deep_research.news.core.card_factory import CardFactory

        assert "update" in CardFactory._card_types

    def test_has_overview_type(self):
        """Test has 'overview' type registered."""
        from local_deep_research.news.core.card_factory import CardFactory

        assert "overview" in CardFactory._card_types


class TestRegisterCardType:
    """Tests for register_card_type method."""

    def test_registers_new_type(self):
        """Test registers new card type."""
        from local_deep_research.news.core.card_factory import CardFactory
        from local_deep_research.news.core.base_card import BaseCard

        class CustomCard(BaseCard):
            pass

        CardFactory.register_card_type("custom", CustomCard)

        assert "custom" in CardFactory._card_types
        assert CardFactory._card_types["custom"] is CustomCard

        # Cleanup
        del CardFactory._card_types["custom"]

    def test_raises_for_non_basecard(self):
        """Test raises ValueError for non-BaseCard class."""
        from local_deep_research.news.core.card_factory import CardFactory

        class NotACard:
            pass

        with pytest.raises(ValueError):
            CardFactory.register_card_type("invalid", NotACard)


class TestGetStorage:
    """Tests for get_storage method."""

    def test_returns_storage_with_session(self):
        """Test returns SQLCardStorage with provided session."""
        from local_deep_research.news.core.card_factory import CardFactory
        from local_deep_research.news.core.card_storage import SQLCardStorage

        mock_session = Mock()
        storage = CardFactory.get_storage(session=mock_session)

        assert isinstance(storage, SQLCardStorage)


class TestCreateCardTypes:
    """Tests for create_card with different types."""

    def test_creates_news_card(self):
        """Test creates NewsCard."""
        from local_deep_research.news.core.card_factory import CardFactory
        from local_deep_research.news.core.base_card import CardSource, NewsCard

        mock_storage = Mock()
        source = CardSource(source_id="test", type="search")

        with patch.object(
            CardFactory, "get_storage", return_value=mock_storage
        ):
            card = CardFactory.create_card(
                card_type="news",
                topic="Test Topic",
                source=source,
                user_id="user123",
            )

        assert isinstance(card, NewsCard)

    def test_creates_research_card(self):
        """Test creates ResearchCard."""
        from local_deep_research.news.core.card_factory import CardFactory
        from local_deep_research.news.core.base_card import (
            CardSource,
            ResearchCard,
        )

        mock_storage = Mock()
        source = CardSource(source_id="test", type="search")

        with patch.object(
            CardFactory, "get_storage", return_value=mock_storage
        ):
            card = CardFactory.create_card(
                card_type="research",
                topic="Test Topic",
                source=source,
                user_id="user123",
            )

        assert isinstance(card, ResearchCard)

    def test_generates_uuid_id(self):
        """Test generates UUID for card ID."""
        from local_deep_research.news.core.card_factory import CardFactory
        from local_deep_research.news.core.base_card import CardSource

        mock_storage = Mock()
        source = CardSource(source_id="test", type="search")

        with patch.object(
            CardFactory, "get_storage", return_value=mock_storage
        ):
            card = CardFactory.create_card(
                card_type="news",
                topic="Test",
                source=source,
                user_id="user123",
            )

        # Verify ID is valid UUID
        uuid.UUID(card.card_id)

    def test_saves_to_storage(self):
        """Test saves card to storage."""
        from local_deep_research.news.core.card_factory import CardFactory
        from local_deep_research.news.core.base_card import CardSource

        mock_storage = Mock()
        source = CardSource(source_id="test", type="search")

        with patch.object(
            CardFactory, "get_storage", return_value=mock_storage
        ):
            CardFactory.create_card(
                card_type="news",
                topic="Test",
                source=source,
                user_id="user123",
            )

        mock_storage.create.assert_called_once()

    def test_raises_for_unknown_type(self):
        """Test raises ValueError for unknown type."""
        from local_deep_research.news.core.card_factory import CardFactory
        from local_deep_research.news.core.base_card import CardSource

        source = CardSource(source_id="test", type="search")

        with pytest.raises(ValueError) as exc_info:
            CardFactory.create_card(
                card_type="unknown_type",
                topic="Test",
                source=source,
                user_id="user123",
            )

        assert "Unknown card type" in str(exc_info.value)


class TestLoadCard:
    """Tests for load_card method."""

    def test_returns_none_for_not_found(self):
        """Test returns None when card not found."""
        from local_deep_research.news.core.card_factory import CardFactory

        mock_storage = Mock()
        mock_storage.get.return_value = None

        with patch.object(
            CardFactory, "get_storage", return_value=mock_storage
        ):
            result = CardFactory.load_card("nonexistent-id")

        assert result is None


class TestGetRecentCards:
    """Tests for get_recent_cards method."""

    def test_has_get_recent_cards_method(self):
        """Test CardFactory has get_recent_cards method."""
        from local_deep_research.news.core.card_factory import CardFactory

        assert hasattr(CardFactory, "get_recent_cards")
        assert callable(CardFactory.get_recent_cards)

    def test_get_recent_cards_accepts_hours(self):
        """Test get_recent_cards accepts hours parameter."""
        from local_deep_research.news.core.card_factory import CardFactory
        import inspect

        sig = inspect.signature(CardFactory.get_recent_cards)
        params = list(sig.parameters.keys())

        assert "hours" in params

    def test_get_recent_cards_accepts_limit(self):
        """Test get_recent_cards accepts limit parameter."""
        from local_deep_research.news.core.card_factory import CardFactory
        import inspect

        sig = inspect.signature(CardFactory.get_recent_cards)
        params = list(sig.parameters.keys())

        assert "limit" in params


class TestUpdateCard:
    """Tests for update_card method."""

    def test_has_update_card_method(self):
        """Test CardFactory has update_card method."""
        from local_deep_research.news.core.card_factory import CardFactory

        assert hasattr(CardFactory, "update_card")
        assert callable(CardFactory.update_card)

    def test_update_card_accepts_card_parameter(self):
        """Test update_card accepts card parameter."""
        from local_deep_research.news.core.card_factory import CardFactory
        import inspect

        sig = inspect.signature(CardFactory.update_card)
        params = list(sig.parameters.keys())

        assert "card" in params


class TestDeleteCard:
    """Tests for delete_card method."""

    def test_calls_storage_delete(self):
        """Test calls storage delete method."""
        from local_deep_research.news.core.card_factory import CardFactory

        mock_storage = Mock()
        mock_storage.delete.return_value = True

        with patch.object(
            CardFactory, "get_storage", return_value=mock_storage
        ):
            CardFactory.delete_card("card-123")

        mock_storage.delete.assert_called_once_with("card-123")


class TestCardFactoryEdgeCases:
    """Edge case tests for CardFactory."""

    def test_create_card_with_extra_kwargs(self):
        """Test create_card passes extra kwargs to card class."""
        from local_deep_research.news.core.card_factory import CardFactory
        from local_deep_research.news.core.base_card import CardSource

        mock_storage = Mock()
        source = CardSource(source_id="test", type="search")

        with patch.object(
            CardFactory, "get_storage", return_value=mock_storage
        ):
            card = CardFactory.create_card(
                card_type="news",
                topic="Test",
                source=source,
                user_id="user123",
                headline="Test Headline",
            )

        assert card.headline == "Test Headline"

    def test_handles_storage_exception(self):
        """Test handles storage exception during save."""
        from local_deep_research.news.core.card_factory import CardFactory
        from local_deep_research.news.core.base_card import CardSource

        mock_storage = Mock()
        mock_storage.create.side_effect = Exception("Storage error")
        source = CardSource(source_id="test", type="search")

        with patch.object(
            CardFactory, "get_storage", return_value=mock_storage
        ):
            with pytest.raises(Exception):
                CardFactory.create_card(
                    card_type="news",
                    topic="Test",
                    source=source,
                    user_id="user123",
                )


class TestCardFactoryImports:
    """Tests for module imports."""

    def test_imports_card_factory(self):
        """Test CardFactory can be imported."""
        from local_deep_research.news.core.card_factory import CardFactory

        assert CardFactory is not None

    def test_card_factory_is_class(self):
        """Test CardFactory is a class."""
        from local_deep_research.news.core.card_factory import CardFactory

        assert isinstance(CardFactory, type)
