"""
Comprehensive tests for core/storage.py abstract interfaces.
Tests BaseStorage, CardStorage, SubscriptionStorage, RatingStorage,
PreferenceStorage, SearchHistoryStorage, and NewsItemStorage.
"""

import pytest
from abc import ABC
import uuid


class TestBaseStorageInterface:
    """Tests for BaseStorage abstract interface."""

    def test_is_abstract_class(self):
        """Test BaseStorage is an abstract class."""
        from local_deep_research.news.core.storage import BaseStorage

        assert issubclass(BaseStorage, ABC)

    def test_cannot_instantiate_directly(self):
        """Test cannot instantiate BaseStorage directly."""
        from local_deep_research.news.core.storage import BaseStorage

        with pytest.raises(TypeError):
            BaseStorage()

    def test_requires_create_method(self):
        """Test requires create method implementation."""
        from local_deep_research.news.core.storage import BaseStorage

        class IncompleteStorage(BaseStorage):
            def get(self, id):
                pass

            def update(self, id, data):
                pass

            def delete(self, id):
                pass

            def list(self, filters=None, limit=100, offset=0):
                pass

        with pytest.raises(TypeError):
            IncompleteStorage()

    def test_requires_get_method(self):
        """Test requires get method implementation."""
        from local_deep_research.news.core.storage import BaseStorage

        class IncompleteStorage(BaseStorage):
            def create(self, data):
                pass

            def update(self, id, data):
                pass

            def delete(self, id):
                pass

            def list(self, filters=None, limit=100, offset=0):
                pass

        with pytest.raises(TypeError):
            IncompleteStorage()

    def test_generate_id_returns_uuid_string(self):
        """Test generate_id returns valid UUID string."""
        from local_deep_research.news.core.storage import BaseStorage

        class ConcreteStorage(BaseStorage):
            def create(self, data):
                return self.generate_id()

            def get(self, id):
                return None

            def update(self, id, data):
                return True

            def delete(self, id):
                return True

            def list(self, filters=None, limit=100, offset=0):
                return []

        storage = ConcreteStorage()
        generated_id = storage.generate_id()

        # Should be valid UUID
        uuid.UUID(generated_id)
        assert isinstance(generated_id, str)


class TestCardStorageInterface:
    """Tests for CardStorage abstract interface."""

    def test_extends_base_storage(self):
        """Test CardStorage extends BaseStorage."""
        from local_deep_research.news.core.storage import (
            CardStorage,
            BaseStorage,
        )

        assert issubclass(CardStorage, BaseStorage)

    def test_cannot_instantiate_directly(self):
        """Test cannot instantiate CardStorage directly."""
        from local_deep_research.news.core.storage import CardStorage

        with pytest.raises(TypeError):
            CardStorage()

    def test_requires_get_by_user_method(self):
        """Test requires get_by_user method."""
        from local_deep_research.news.core.storage import CardStorage

        # Define complete BaseStorage methods but missing CardStorage methods
        class IncompleteCardStorage(CardStorage):
            def create(self, data):
                pass

            def get(self, id):
                pass

            def update(self, id, data):
                pass

            def delete(self, id):
                pass

            def list(self, filters=None, limit=100, offset=0):
                pass

            def get_latest_version(self, card_id):
                pass

            def add_version(self, card_id, version_data):
                pass

            def update_latest_info(self, card_id, version_data):
                pass

            def archive_card(self, card_id):
                pass

            def pin_card(self, card_id, pinned=True):
                pass

        with pytest.raises(TypeError):
            IncompleteCardStorage()

    def test_requires_archive_card_method(self):
        """Test requires archive_card method."""
        from local_deep_research.news.core.storage import CardStorage

        abstract_methods = CardStorage.__abstractmethods__

        assert "archive_card" in abstract_methods

    def test_requires_pin_card_method(self):
        """Test requires pin_card method."""
        from local_deep_research.news.core.storage import CardStorage

        abstract_methods = CardStorage.__abstractmethods__

        assert "pin_card" in abstract_methods


class TestSubscriptionStorageInterface:
    """Tests for SubscriptionStorage abstract interface."""

    def test_extends_base_storage(self):
        """Test SubscriptionStorage extends BaseStorage."""
        from local_deep_research.news.core.storage import (
            SubscriptionStorage,
            BaseStorage,
        )

        assert issubclass(SubscriptionStorage, BaseStorage)

    def test_cannot_instantiate_directly(self):
        """Test cannot instantiate directly."""
        from local_deep_research.news.core.storage import SubscriptionStorage

        with pytest.raises(TypeError):
            SubscriptionStorage()

    def test_requires_get_active_subscriptions_method(self):
        """Test requires get_active_subscriptions method."""
        from local_deep_research.news.core.storage import SubscriptionStorage

        abstract_methods = SubscriptionStorage.__abstractmethods__

        assert "get_active_subscriptions" in abstract_methods

    def test_requires_get_due_subscriptions_method(self):
        """Test requires get_due_subscriptions method."""
        from local_deep_research.news.core.storage import SubscriptionStorage

        abstract_methods = SubscriptionStorage.__abstractmethods__

        assert "get_due_subscriptions" in abstract_methods

    def test_requires_update_refresh_time_method(self):
        """Test requires update_refresh_time method."""
        from local_deep_research.news.core.storage import SubscriptionStorage

        abstract_methods = SubscriptionStorage.__abstractmethods__

        assert "update_refresh_time" in abstract_methods

    def test_requires_pause_subscription_method(self):
        """Test requires pause_subscription method."""
        from local_deep_research.news.core.storage import SubscriptionStorage

        abstract_methods = SubscriptionStorage.__abstractmethods__

        assert "pause_subscription" in abstract_methods

    def test_requires_resume_subscription_method(self):
        """Test requires resume_subscription method."""
        from local_deep_research.news.core.storage import SubscriptionStorage

        abstract_methods = SubscriptionStorage.__abstractmethods__

        assert "resume_subscription" in abstract_methods

    def test_requires_expire_subscription_method(self):
        """Test requires expire_subscription method."""
        from local_deep_research.news.core.storage import SubscriptionStorage

        abstract_methods = SubscriptionStorage.__abstractmethods__

        assert "expire_subscription" in abstract_methods


class TestRatingStorageInterface:
    """Tests for RatingStorage abstract interface."""

    def test_extends_base_storage(self):
        """Test RatingStorage extends BaseStorage."""
        from local_deep_research.news.core.storage import (
            RatingStorage,
            BaseStorage,
        )

        assert issubclass(RatingStorage, BaseStorage)

    def test_cannot_instantiate_directly(self):
        """Test cannot instantiate directly."""
        from local_deep_research.news.core.storage import RatingStorage

        with pytest.raises(TypeError):
            RatingStorage()

    def test_requires_get_user_rating_method(self):
        """Test requires get_user_rating method."""
        from local_deep_research.news.core.storage import RatingStorage

        abstract_methods = RatingStorage.__abstractmethods__

        assert "get_user_rating" in abstract_methods

    def test_requires_upsert_rating_method(self):
        """Test requires upsert_rating method."""
        from local_deep_research.news.core.storage import RatingStorage

        abstract_methods = RatingStorage.__abstractmethods__

        assert "upsert_rating" in abstract_methods

    def test_requires_get_ratings_summary_method(self):
        """Test requires get_ratings_summary method."""
        from local_deep_research.news.core.storage import RatingStorage

        abstract_methods = RatingStorage.__abstractmethods__

        assert "get_ratings_summary" in abstract_methods

    def test_requires_get_user_ratings_method(self):
        """Test requires get_user_ratings method."""
        from local_deep_research.news.core.storage import RatingStorage

        abstract_methods = RatingStorage.__abstractmethods__

        assert "get_user_ratings" in abstract_methods


class TestPreferenceStorageInterface:
    """Tests for PreferenceStorage abstract interface."""

    def test_extends_base_storage(self):
        """Test PreferenceStorage extends BaseStorage."""
        from local_deep_research.news.core.storage import (
            PreferenceStorage,
            BaseStorage,
        )

        assert issubclass(PreferenceStorage, BaseStorage)

    def test_cannot_instantiate_directly(self):
        """Test cannot instantiate directly."""
        from local_deep_research.news.core.storage import PreferenceStorage

        with pytest.raises(TypeError):
            PreferenceStorage()

    def test_requires_get_user_preferences_method(self):
        """Test requires get_user_preferences method."""
        from local_deep_research.news.core.storage import PreferenceStorage

        abstract_methods = PreferenceStorage.__abstractmethods__

        assert "get_user_preferences" in abstract_methods

    def test_requires_upsert_preferences_method(self):
        """Test requires upsert_preferences method."""
        from local_deep_research.news.core.storage import PreferenceStorage

        abstract_methods = PreferenceStorage.__abstractmethods__

        assert "upsert_preferences" in abstract_methods

    def test_requires_add_liked_item_method(self):
        """Test requires add_liked_item method."""
        from local_deep_research.news.core.storage import PreferenceStorage

        abstract_methods = PreferenceStorage.__abstractmethods__

        assert "add_liked_item" in abstract_methods

    def test_requires_add_disliked_item_method(self):
        """Test requires add_disliked_item method."""
        from local_deep_research.news.core.storage import PreferenceStorage

        abstract_methods = PreferenceStorage.__abstractmethods__

        assert "add_disliked_item" in abstract_methods

    def test_requires_update_preference_embedding_method(self):
        """Test requires update_preference_embedding method."""
        from local_deep_research.news.core.storage import PreferenceStorage

        abstract_methods = PreferenceStorage.__abstractmethods__

        assert "update_preference_embedding" in abstract_methods


class TestSearchHistoryStorageInterface:
    """Tests for SearchHistoryStorage abstract interface."""

    def test_extends_base_storage(self):
        """Test SearchHistoryStorage extends BaseStorage."""
        from local_deep_research.news.core.storage import (
            SearchHistoryStorage,
            BaseStorage,
        )

        assert issubclass(SearchHistoryStorage, BaseStorage)

    def test_cannot_instantiate_directly(self):
        """Test cannot instantiate directly."""
        from local_deep_research.news.core.storage import SearchHistoryStorage

        with pytest.raises(TypeError):
            SearchHistoryStorage()

    def test_requires_record_search_method(self):
        """Test requires record_search method."""
        from local_deep_research.news.core.storage import SearchHistoryStorage

        abstract_methods = SearchHistoryStorage.__abstractmethods__

        assert "record_search" in abstract_methods

    def test_requires_get_recent_searches_method(self):
        """Test requires get_recent_searches method."""
        from local_deep_research.news.core.storage import SearchHistoryStorage

        abstract_methods = SearchHistoryStorage.__abstractmethods__

        assert "get_recent_searches" in abstract_methods

    def test_requires_link_to_subscription_method(self):
        """Test requires link_to_subscription method."""
        from local_deep_research.news.core.storage import SearchHistoryStorage

        abstract_methods = SearchHistoryStorage.__abstractmethods__

        assert "link_to_subscription" in abstract_methods

    def test_requires_get_popular_searches_method(self):
        """Test requires get_popular_searches method."""
        from local_deep_research.news.core.storage import SearchHistoryStorage

        abstract_methods = SearchHistoryStorage.__abstractmethods__

        assert "get_popular_searches" in abstract_methods


class TestNewsItemStorageInterface:
    """Tests for NewsItemStorage abstract interface."""

    def test_extends_base_storage(self):
        """Test NewsItemStorage extends BaseStorage."""
        from local_deep_research.news.core.storage import (
            NewsItemStorage,
            BaseStorage,
        )

        assert issubclass(NewsItemStorage, BaseStorage)

    def test_cannot_instantiate_directly(self):
        """Test cannot instantiate directly."""
        from local_deep_research.news.core.storage import NewsItemStorage

        with pytest.raises(TypeError):
            NewsItemStorage()

    def test_requires_get_recent_method(self):
        """Test requires get_recent method."""
        from local_deep_research.news.core.storage import NewsItemStorage

        abstract_methods = NewsItemStorage.__abstractmethods__

        assert "get_recent" in abstract_methods

    def test_requires_store_batch_method(self):
        """Test requires store_batch method."""
        from local_deep_research.news.core.storage import NewsItemStorage

        abstract_methods = NewsItemStorage.__abstractmethods__

        assert "store_batch" in abstract_methods

    def test_requires_update_votes_method(self):
        """Test requires update_votes method."""
        from local_deep_research.news.core.storage import NewsItemStorage

        abstract_methods = NewsItemStorage.__abstractmethods__

        assert "update_votes" in abstract_methods

    def test_requires_get_by_category_method(self):
        """Test requires get_by_category method."""
        from local_deep_research.news.core.storage import NewsItemStorage

        abstract_methods = NewsItemStorage.__abstractmethods__

        assert "get_by_category" in abstract_methods

    def test_requires_cleanup_old_items_method(self):
        """Test requires cleanup_old_items method."""
        from local_deep_research.news.core.storage import NewsItemStorage

        abstract_methods = NewsItemStorage.__abstractmethods__

        assert "cleanup_old_items" in abstract_methods


class TestConcreteBaseStorageImplementation:
    """Tests for a concrete BaseStorage implementation."""

    def test_concrete_implementation_works(self):
        """Test concrete implementation can be instantiated."""
        from local_deep_research.news.core.storage import BaseStorage

        class InMemoryStorage(BaseStorage):
            def __init__(self):
                self.data = {}

            def create(self, data):
                id = self.generate_id()
                self.data[id] = data
                return id

            def get(self, id):
                return self.data.get(id)

            def update(self, id, data):
                if id in self.data:
                    self.data[id].update(data)
                    return True
                return False

            def delete(self, id):
                if id in self.data:
                    del self.data[id]
                    return True
                return False

            def list(self, filters=None, limit=100, offset=0):
                return list(self.data.values())[offset : offset + limit]

        storage = InMemoryStorage()
        assert storage is not None

    def test_create_returns_id(self):
        """Test create returns a valid ID."""
        from local_deep_research.news.core.storage import BaseStorage

        class InMemoryStorage(BaseStorage):
            def __init__(self):
                self.data = {}

            def create(self, data):
                id = self.generate_id()
                self.data[id] = data
                return id

            def get(self, id):
                return self.data.get(id)

            def update(self, id, data):
                return True

            def delete(self, id):
                return True

            def list(self, filters=None, limit=100, offset=0):
                return []

        storage = InMemoryStorage()
        id = storage.create({"name": "test"})

        assert id is not None
        assert isinstance(id, str)
        uuid.UUID(id)  # Validates it's a UUID

    def test_get_returns_created_data(self):
        """Test get returns the created data."""
        from local_deep_research.news.core.storage import BaseStorage

        class InMemoryStorage(BaseStorage):
            def __init__(self):
                self.data = {}

            def create(self, data):
                id = self.generate_id()
                self.data[id] = data
                return id

            def get(self, id):
                return self.data.get(id)

            def update(self, id, data):
                return True

            def delete(self, id):
                return True

            def list(self, filters=None, limit=100, offset=0):
                return []

        storage = InMemoryStorage()
        test_data = {"name": "test", "value": 42}
        id = storage.create(test_data)

        result = storage.get(id)

        assert result == test_data


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

    def test_imports_base_storage(self):
        """Test BaseStorage can be imported."""
        from local_deep_research.news.core.storage import BaseStorage

        assert BaseStorage is not None

    def test_imports_card_storage(self):
        """Test CardStorage can be imported."""
        from local_deep_research.news.core.storage import CardStorage

        assert CardStorage is not None

    def test_imports_subscription_storage(self):
        """Test SubscriptionStorage can be imported."""
        from local_deep_research.news.core.storage import SubscriptionStorage

        assert SubscriptionStorage is not None

    def test_imports_rating_storage(self):
        """Test RatingStorage can be imported."""
        from local_deep_research.news.core.storage import RatingStorage

        assert RatingStorage is not None

    def test_imports_preference_storage(self):
        """Test PreferenceStorage can be imported."""
        from local_deep_research.news.core.storage import PreferenceStorage

        assert PreferenceStorage is not None

    def test_imports_search_history_storage(self):
        """Test SearchHistoryStorage can be imported."""
        from local_deep_research.news.core.storage import SearchHistoryStorage

        assert SearchHistoryStorage is not None

    def test_imports_news_item_storage(self):
        """Test NewsItemStorage can be imported."""
        from local_deep_research.news.core.storage import NewsItemStorage

        assert NewsItemStorage is not None
