"""
Extended tests for news/subscription_manager/storage.py

Tests cover:
- SQLSubscriptionStorage initialization
- CRUD operations (create, get, update, delete)
- list() with various filters
- get_active_subscriptions() - active subscription queries
- get_due_subscriptions() - due subscription queries
- update_refresh_time() - timestamp updates
- increment_stats() - statistics updates
- pause_subscription() / resume_subscription() - status changes
- expire_subscription() - expiration handling
- Edge cases and error handling
"""

from unittest.mock import MagicMock, patch
from datetime import datetime, timezone, timedelta


class TestSQLSubscriptionStorageInit:
    """Tests for SQLSubscriptionStorage initialization."""

    def test_init_with_valid_session(self):
        """Initialization with valid session succeeds."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        storage = SQLSubscriptionStorage(mock_session)

        assert storage._session is mock_session


class TestSQLSubscriptionStorageSessionProperty:
    """Tests for session property accessor."""

    def test_session_property_returns_session(self):
        """Session property returns the stored session."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        storage = SQLSubscriptionStorage(mock_session)

        assert storage.session is mock_session


class TestSQLSubscriptionStorageCreate:
    """Tests for create method."""

    def test_create_with_id_uses_provided_id(self):
        """Uses provided ID when available."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        storage = SQLSubscriptionStorage(mock_session)

        data = {
            "id": "sub-123",
            "user_id": "user-456",
            "subscription_type": "search",
            "query_or_topic": "AI news",
            "refresh_interval_minutes": 60,
        }

        with patch(
            "local_deep_research.news.subscription_manager.storage.NewsSubscription"
        ) as MockSub:
            mock_sub = MagicMock()
            MockSub.return_value = mock_sub

            result = storage.create(data)

            assert result == "sub-123"

    def test_create_without_id_generates_uuid(self):
        """Generates UUID when ID not provided."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        storage = SQLSubscriptionStorage(mock_session)

        data = {
            "user_id": "user-456",
            "subscription_type": "search",
            "query_or_topic": "AI news",
            "refresh_interval_minutes": 60,
        }

        with patch(
            "local_deep_research.news.subscription_manager.storage.NewsSubscription"
        ) as MockSub:
            mock_sub = MagicMock()
            MockSub.return_value = mock_sub

            result = storage.create(data)

            assert len(result) == 36  # UUID format

    def test_create_calculates_next_refresh(self):
        """next_refresh is calculated from refresh_interval_minutes."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        storage = SQLSubscriptionStorage(mock_session)

        data = {
            "user_id": "user-456",
            "subscription_type": "search",
            "query_or_topic": "AI news",
            "refresh_interval_minutes": 120,
        }

        before = datetime.now(timezone.utc)

        with patch(
            "local_deep_research.news.subscription_manager.storage.NewsSubscription"
        ) as MockSub:
            mock_sub = MagicMock()
            MockSub.return_value = mock_sub

            storage.create(data)

            call_kwargs = MockSub.call_args[1]
            next_refresh = call_kwargs["next_refresh"]
            after = datetime.now(timezone.utc)

            # next_refresh should be approximately now + 120 minutes
            expected_min = before + timedelta(minutes=120)
            expected_max = after + timedelta(minutes=120)
            assert expected_min <= next_refresh <= expected_max

    def test_create_with_all_optional_fields(self):
        """All optional fields are passed correctly."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        storage = SQLSubscriptionStorage(mock_session)

        data = {
            "user_id": "user-456",
            "subscription_type": "topic",
            "query_or_topic": "Technology",
            "refresh_interval_minutes": 60,
            "name": "My Sub",
            "frequency": "weekly",
            "source_type": "rss",
            "source_id": "feed-1",
            "created_from": "import",
            "folder": "Tech",
            "folder_id": "folder-1",
            "notes": "Test notes",
            "status": "active",
            "is_active": True,
            "model_provider": "openai",
            "model": "gpt-4",
            "search_strategy": "news",
            "custom_endpoint": None,
            "search_engine": "google",
            "search_iterations": 5,
            "questions_per_iteration": 3,
        }

        with patch(
            "local_deep_research.news.subscription_manager.storage.NewsSubscription"
        ) as MockSub:
            mock_sub = MagicMock()
            MockSub.return_value = mock_sub

            storage.create(data)

            call_kwargs = MockSub.call_args[1]
            assert call_kwargs["name"] == "My Sub"
            assert call_kwargs["frequency"] == "weekly"
            assert call_kwargs["search_iterations"] == 5


class TestSQLSubscriptionStorageGet:
    """Tests for get method."""

    def test_get_existing_subscription(self):
        """Returns subscription data when found."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_sub = MagicMock()
        mock_sub.id = "sub-123"
        mock_sub.user_id = "user-456"
        mock_sub.name = "Test Sub"
        mock_sub.subscription_type = "search"
        mock_sub.query_or_topic = "AI news"
        mock_sub.refresh_interval_minutes = 60
        mock_sub.created_at = datetime.now(timezone.utc)
        mock_sub.updated_at = None
        mock_sub.last_refresh = None
        mock_sub.next_refresh = None
        mock_sub.expires_at = None
        mock_sub.source_type = None
        mock_sub.source_id = None
        mock_sub.created_from = None
        mock_sub.folder = None
        mock_sub.folder_id = None
        mock_sub.notes = None
        mock_sub.status = "active"
        mock_sub.refresh_count = 0
        mock_sub.results_count = 0
        mock_sub.last_error = None
        mock_sub.error_count = 0

        mock_context.query.return_value.filter_by.return_value.first.return_value = mock_sub

        storage = SQLSubscriptionStorage(mock_session)
        result = storage.get("sub-123")

        assert result is not None
        assert result["id"] == "sub-123"
        assert result["user_id"] == "user-456"
        assert result["name"] == "Test Sub"

    def test_get_nonexistent_subscription(self):
        """Returns None when subscription not found."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_context.query.return_value.filter_by.return_value.first.return_value = None

        storage = SQLSubscriptionStorage(mock_session)
        result = storage.get("nonexistent")

        assert result is None


class TestSQLSubscriptionStorageUpdate:
    """Tests for update method."""

    def test_update_existing_subscription(self):
        """Updates subscription and returns True."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_sub = MagicMock()
        mock_sub.id = "sub-123"
        mock_context.query.return_value.filter_by.return_value.first.return_value = mock_sub

        storage = SQLSubscriptionStorage(mock_session)
        result = storage.update("sub-123", {"name": "Updated Name"})

        assert result is True
        assert mock_sub.name == "Updated Name"
        mock_context.commit.assert_called_once()

    def test_update_nonexistent_subscription(self):
        """Returns False when subscription not found."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_context.query.return_value.filter_by.return_value.first.return_value = None

        storage = SQLSubscriptionStorage(mock_session)
        result = storage.update("nonexistent", {"name": "New Name"})

        assert result is False

    def test_update_recalculates_next_refresh(self):
        """Recalculates next_refresh when interval changes."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_sub = MagicMock()
        mock_sub.id = "sub-123"
        mock_context.query.return_value.filter_by.return_value.first.return_value = mock_sub

        storage = SQLSubscriptionStorage(mock_session)
        before = datetime.now(timezone.utc)
        storage.update("sub-123", {"refresh_interval_minutes": 180})
        after = datetime.now(timezone.utc)

        expected_min = before + timedelta(minutes=180)
        expected_max = after + timedelta(minutes=180)
        assert expected_min <= mock_sub.next_refresh <= expected_max

    def test_update_only_updateable_fields(self):
        """Only updateable fields are modified."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_sub = MagicMock()
        mock_sub.id = "sub-123"
        mock_sub.user_id = "user-456"  # Should not be updateable
        mock_context.query.return_value.filter_by.return_value.first.return_value = mock_sub

        storage = SQLSubscriptionStorage(mock_session)
        storage.update(
            "sub-123",
            {
                "name": "New Name",
                "user_id": "new-user",  # Not in updateable fields
                "status": "paused",
            },
        )

        assert mock_sub.name == "New Name"
        assert mock_sub.status == "paused"
        # user_id should not have been updated


class TestSQLSubscriptionStorageDelete:
    """Tests for delete method."""

    def test_delete_existing_subscription(self):
        """Deletes subscription and returns True."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_sub = MagicMock()
        mock_context.query.return_value.filter_by.return_value.first.return_value = mock_sub

        storage = SQLSubscriptionStorage(mock_session)
        result = storage.delete("sub-123")

        assert result is True
        mock_context.delete.assert_called_once_with(mock_sub)
        mock_context.commit.assert_called_once()

    def test_delete_nonexistent_subscription(self):
        """Returns False when subscription not found."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_context.query.return_value.filter_by.return_value.first.return_value = None

        storage = SQLSubscriptionStorage(mock_session)
        result = storage.delete("nonexistent")

        assert result is False


class TestSQLSubscriptionStorageList:
    """Tests for list method."""

    def test_list_no_filters(self):
        """Returns all subscriptions when no filters."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_sub1 = MagicMock()
        mock_sub1.id = "sub-1"
        mock_sub1.user_id = "user-1"
        mock_sub1.name = "Sub 1"
        mock_sub1.subscription_type = "search"
        mock_sub1.query_or_topic = "Topic 1"
        mock_sub1.refresh_interval_minutes = 60
        mock_sub1.created_at = datetime.now(timezone.utc)
        mock_sub1.updated_at = None
        mock_sub1.last_refresh = None
        mock_sub1.next_refresh = None
        mock_sub1.status = "active"
        mock_sub1.folder = None
        mock_sub1.notes = None

        mock_context.query.return_value.limit.return_value.offset.return_value.all.return_value = [
            mock_sub1
        ]

        storage = SQLSubscriptionStorage(mock_session)
        result = storage.list()

        assert len(result) == 1
        assert result[0]["id"] == "sub-1"

    def test_list_with_user_id_filter(self):
        """Filters by user_id when provided."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_query = MagicMock()
        mock_context.query.return_value = mock_query
        mock_query.filter_by.return_value = mock_query
        mock_query.limit.return_value = mock_query
        mock_query.offset.return_value = mock_query
        mock_query.all.return_value = []

        storage = SQLSubscriptionStorage(mock_session)
        storage.list(filters={"user_id": "user-123"})

        mock_query.filter_by.assert_called_with(user_id="user-123")

    def test_list_with_pagination(self):
        """Applies limit and offset correctly."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_query = MagicMock()
        mock_context.query.return_value = mock_query
        mock_query.limit.return_value = mock_query
        mock_query.offset.return_value = mock_query
        mock_query.all.return_value = []

        storage = SQLSubscriptionStorage(mock_session)
        storage.list(limit=50, offset=10)

        mock_query.limit.assert_called_with(50)
        mock_query.offset.assert_called_with(10)


class TestSQLSubscriptionStorageGetActiveSubscriptions:
    """Tests for get_active_subscriptions method."""

    def test_get_active_subscriptions_method_exists(self):
        """Method exists with correct signature."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )
        import inspect

        mock_session = MagicMock()
        storage = SQLSubscriptionStorage(mock_session)

        assert hasattr(storage, "get_active_subscriptions")

        sig = inspect.signature(storage.get_active_subscriptions)
        params = sig.parameters
        assert "user_id" in params

    def test_get_active_subscriptions_returns_list(self):
        """Returns a list."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_sub = MagicMock()
        mock_sub.to_dict.return_value = {"id": "sub-1", "status": "active"}

        mock_query = MagicMock()
        mock_context.query.return_value = mock_query
        mock_query.filter_by.return_value = mock_query
        mock_query.all.return_value = [mock_sub]

        storage = SQLSubscriptionStorage(mock_session)
        result = storage.get_active_subscriptions()

        assert isinstance(result, list)


class TestSQLSubscriptionStorageGetDueSubscriptions:
    """Tests for get_due_subscriptions method."""

    def test_get_due_subscriptions(self):
        """Returns subscriptions that are due for refresh."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_sub = MagicMock()
        mock_sub.to_dict.return_value = {"id": "sub-1"}

        mock_query = MagicMock()
        mock_context.query.return_value = mock_query
        mock_query.filter.return_value = mock_query
        mock_query.limit.return_value = mock_query
        mock_query.all.return_value = [mock_sub]

        storage = SQLSubscriptionStorage(mock_session)
        result = storage.get_due_subscriptions()

        assert len(result) == 1

    def test_get_due_subscriptions_respects_limit(self):
        """Respects the limit parameter."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_query = MagicMock()
        mock_context.query.return_value = mock_query
        mock_query.filter.return_value = mock_query
        mock_query.limit.return_value = mock_query
        mock_query.all.return_value = []

        storage = SQLSubscriptionStorage(mock_session)
        storage.get_due_subscriptions(limit=25)

        mock_query.limit.assert_called_with(25)


class TestSQLSubscriptionStorageUpdateRefreshTime:
    """Tests for update_refresh_time method."""

    def test_update_refresh_time_success(self):
        """Updates refresh timestamps correctly."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_sub = MagicMock()
        mock_context.query.return_value.filter_by.return_value.first.return_value = mock_sub

        last_refresh = datetime(2024, 1, 15, 12, 0, 0, tzinfo=timezone.utc)
        next_refresh = datetime(2024, 1, 15, 13, 0, 0, tzinfo=timezone.utc)

        storage = SQLSubscriptionStorage(mock_session)
        result = storage.update_refresh_time(
            "sub-123", last_refresh, next_refresh
        )

        assert result is True
        assert mock_sub.last_refresh == last_refresh
        assert mock_sub.next_refresh == next_refresh
        mock_context.commit.assert_called_once()

    def test_update_refresh_time_not_found(self):
        """Returns False when subscription not found."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_context.query.return_value.filter_by.return_value.first.return_value = None

        storage = SQLSubscriptionStorage(mock_session)
        result = storage.update_refresh_time(
            "nonexistent",
            datetime.now(timezone.utc),
            datetime.now(timezone.utc),
        )

        assert result is False


class TestSQLSubscriptionStorageIncrementStats:
    """Tests for increment_stats method."""

    def test_increment_stats_success(self):
        """Increments stats correctly."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_sub = MagicMock()
        mock_sub.refresh_count = 5
        mock_context.query.return_value.filter_by.return_value.first.return_value = mock_sub

        storage = SQLSubscriptionStorage(mock_session)
        result = storage.increment_stats("sub-123", results_count=10)

        assert result is True
        assert mock_sub.refresh_count == 6
        assert mock_sub.total_runs == 6
        assert mock_sub.results_count == 10

    def test_increment_stats_not_found(self):
        """Returns False when subscription not found."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_context.query.return_value.filter_by.return_value.first.return_value = None

        storage = SQLSubscriptionStorage(mock_session)
        result = storage.increment_stats("nonexistent", 10)

        assert result is False


class TestSQLSubscriptionStoragePauseSubscription:
    """Tests for pause_subscription method."""

    def test_pause_subscription_success(self):
        """Pauses subscription correctly."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_sub = MagicMock()
        mock_context.query.return_value.filter_by.return_value.first.return_value = mock_sub

        storage = SQLSubscriptionStorage(mock_session)
        result = storage.pause_subscription("sub-123")

        assert result is True
        mock_context.commit.assert_called_once()

    def test_pause_subscription_not_found(self):
        """Returns False when subscription not found."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_context.query.return_value.filter_by.return_value.first.return_value = None

        storage = SQLSubscriptionStorage(mock_session)
        result = storage.pause_subscription("nonexistent")

        assert result is False


class TestSQLSubscriptionStorageResumeSubscription:
    """Tests for resume_subscription method."""

    def test_resume_subscription_method_exists(self):
        """Method exists with correct signature."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )
        import inspect

        mock_session = MagicMock()
        storage = SQLSubscriptionStorage(mock_session)

        assert hasattr(storage, "resume_subscription")

        sig = inspect.signature(storage.resume_subscription)
        params = list(sig.parameters.keys())
        assert "subscription_id" in params

    def test_resume_subscription_not_found(self):
        """Returns False when subscription not found."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_context.query.return_value.filter_by.return_value.first.return_value = None

        storage = SQLSubscriptionStorage(mock_session)
        result = storage.resume_subscription("nonexistent")

        assert result is False

    def test_resume_subscription_returns_bool(self):
        """Returns a boolean."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_context.query.return_value.filter_by.return_value.first.return_value = None

        storage = SQLSubscriptionStorage(mock_session)
        result = storage.resume_subscription("sub-123")

        assert isinstance(result, bool)


class TestSQLSubscriptionStorageExpireSubscription:
    """Tests for expire_subscription method."""

    def test_expire_subscription_success(self):
        """Expires subscription correctly."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_sub = MagicMock()
        mock_context.query.return_value.filter_by.return_value.first.return_value = mock_sub

        storage = SQLSubscriptionStorage(mock_session)
        result = storage.expire_subscription("sub-123")

        assert result is True
        mock_context.commit.assert_called_once()

    def test_expire_subscription_not_found(self):
        """Returns False when subscription not found."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        mock_context = MagicMock()
        mock_session.__enter__ = MagicMock(return_value=mock_context)
        mock_session.__exit__ = MagicMock(return_value=False)

        mock_context.query.return_value.filter_by.return_value.first.return_value = None

        storage = SQLSubscriptionStorage(mock_session)
        result = storage.expire_subscription("nonexistent")

        assert result is False


class TestSQLSubscriptionStorageInheritance:
    """Tests for SQLSubscriptionStorage inheritance."""

    def test_inherits_from_subscription_storage(self):
        """Inherits from SubscriptionStorage base class."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )
        from local_deep_research.news.core.storage import SubscriptionStorage

        assert issubclass(SQLSubscriptionStorage, SubscriptionStorage)

    def test_inherits_generate_id(self):
        """Inherits generate_id method from base."""
        from local_deep_research.news.subscription_manager.storage import (
            SQLSubscriptionStorage,
        )

        mock_session = MagicMock()
        storage = SQLSubscriptionStorage(mock_session)

        result = storage.generate_id()

        assert isinstance(result, str)
        assert len(result) == 36
