"""
Comprehensive tests for core/storage.py abstract interfaces.
Tests BaseStorage, CardStorage, 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 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 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
