"""
Deep behavioral tests for InteractionType enum and StorageManager interaction logic.
Tests enum values, interaction recording patterns, and user stats calculation.
"""

from unittest.mock import Mock

import pytest

from local_deep_research.news.core.storage_manager import InteractionType


# --- InteractionType enum ---


class TestInteractionType:
    """Tests for InteractionType enum values."""

    def test_view_value(self):
        assert InteractionType.VIEW.value == "view"

    def test_vote_up_value(self):
        assert InteractionType.VOTE_UP.value == "vote_up"

    def test_vote_down_value(self):
        assert InteractionType.VOTE_DOWN.value == "vote_down"

    def test_research_value(self):
        assert InteractionType.RESEARCH.value == "research"

    def test_share_value(self):
        assert InteractionType.SHARE.value == "share"

    def test_total_count(self):
        assert len(InteractionType) == 5

    def test_from_string_view(self):
        assert InteractionType("view") == InteractionType.VIEW

    def test_from_string_vote_up(self):
        assert InteractionType("vote_up") == InteractionType.VOTE_UP

    def test_invalid_value_raises(self):
        with pytest.raises(ValueError):
            InteractionType("invalid")

    def test_enum_is_iterable(self):
        values = [t.value for t in InteractionType]
        assert "view" in values
        assert "vote_up" in values
        assert "vote_down" in values
        assert "research" in values
        assert "share" in values

    def test_enum_name_matches(self):
        assert InteractionType.VIEW.name == "VIEW"
        assert InteractionType.VOTE_UP.name == "VOTE_UP"

    def test_enum_comparison(self):
        assert InteractionType.VIEW == InteractionType.VIEW
        assert InteractionType.VIEW != InteractionType.VOTE_UP

    def test_enum_identity(self):
        assert InteractionType.VIEW is InteractionType.VIEW

    def test_enum_hashing(self):
        """Enums should be hashable for use as dict keys."""
        d = {InteractionType.VIEW: "viewed", InteractionType.VOTE_UP: "upvoted"}
        assert d[InteractionType.VIEW] == "viewed"


# --- StorageManager interaction patterns ---


class TestStorageManagerInteractionPatterns:
    """Tests for how StorageManager handles different interaction types.

    These test the interaction recording logic by verifying the card
    mutation patterns for each interaction type.
    """

    def _make_card_with_interaction(self):
        """Create a mock card with an interaction dict."""
        card = Mock()
        card.interaction = {
            "views": 0,
            "votes_up": 0,
            "votes_down": 0,
        }
        return card

    def test_view_increments_view_count(self):
        card = self._make_card_with_interaction()
        # Simulate VIEW interaction logic from StorageManager.record_interaction
        card.interaction["viewed"] = True
        card.interaction["views"] = card.interaction.get("views", 0) + 1
        assert card.interaction["views"] == 1
        assert card.interaction["viewed"] is True

    def test_view_multiple_times(self):
        card = self._make_card_with_interaction()
        for _ in range(5):
            card.interaction["views"] = card.interaction.get("views", 0) + 1
        assert card.interaction["views"] == 5

    def test_vote_up_sets_voted_up(self):
        card = self._make_card_with_interaction()
        card.interaction["voted"] = "up"
        card.interaction["votes_up"] = card.interaction.get("votes_up", 0) + 1
        assert card.interaction["voted"] == "up"
        assert card.interaction["votes_up"] == 1

    def test_vote_down_sets_voted_down(self):
        card = self._make_card_with_interaction()
        card.interaction["voted"] = "down"
        card.interaction["votes_down"] = (
            card.interaction.get("votes_down", 0) + 1
        )
        assert card.interaction["voted"] == "down"
        assert card.interaction["votes_down"] == 1

    def test_research_sets_researched_flag(self):
        card = self._make_card_with_interaction()
        card.interaction["researched"] = True
        card.interaction["research_count"] = (
            card.interaction.get("research_count", 0) + 1
        )
        assert card.interaction["researched"] is True
        assert card.interaction["research_count"] == 1

    def test_research_multiple_times(self):
        card = self._make_card_with_interaction()
        for _ in range(3):
            card.interaction["researched"] = True
            card.interaction["research_count"] = (
                card.interaction.get("research_count", 0) + 1
            )
        assert card.interaction["research_count"] == 3

    def test_metadata_stored_with_interaction(self):
        card = self._make_card_with_interaction()
        metadata = {"source": "button", "position": 3}
        interaction_type = InteractionType.VIEW
        card.interaction[f"{interaction_type}_metadata"] = metadata
        assert card.interaction[f"{interaction_type}_metadata"] == metadata


# --- User stats calculation patterns ---


class TestUserStatsCalculation:
    """Tests for the stats calculation logic used in get_user_stats."""

    def test_count_votes_up(self):
        ratings = [
            {"value": 1},
            {"value": 1},
            {"value": -1},
            {"value": 1},
        ]
        votes_up = sum(1 for r in ratings if r.get("value", 0) > 0)
        assert votes_up == 3

    def test_count_votes_down(self):
        ratings = [
            {"value": 1},
            {"value": -1},
            {"value": -1},
        ]
        votes_down = sum(1 for r in ratings if r.get("value", 0) < 0)
        assert votes_down == 2

    def test_count_total_views(self):
        user_cards = [
            {"interaction": {"views": 10}},
            {"interaction": {"views": 5}},
            {"interaction": {}},
        ]
        total_views = sum(
            c.get("interaction", {}).get("views", 0) for c in user_cards
        )
        assert total_views == 15

    def test_empty_ratings(self):
        ratings = []
        votes_up = sum(1 for r in ratings if r.get("value", 0) > 0)
        votes_down = sum(1 for r in ratings if r.get("value", 0) < 0)
        assert votes_up == 0
        assert votes_down == 0

    def test_missing_value_in_rating(self):
        ratings = [{"other": "data"}]
        votes_up = sum(1 for r in ratings if r.get("value", 0) > 0)
        assert votes_up == 0

    def test_zero_value_counts_neither(self):
        ratings = [{"value": 0}]
        votes_up = sum(1 for r in ratings if r.get("value", 0) > 0)
        votes_down = sum(1 for r in ratings if r.get("value", 0) < 0)
        assert votes_up == 0
        assert votes_down == 0


# --- Card interaction conversion patterns ---


class TestCardInteractionConversion:
    """Tests for converting ratings to interaction format (get_card_interactions logic)."""

    def test_positive_rating_is_upvote(self):
        rating = {"user_id": "u1", "value": 1, "created_at": "2025-01-01"}
        interaction = {
            "user_id": rating.get("user_id"),
            "interaction_type": "vote",
            "interaction_data": {
                "vote": "up" if rating.get("value", 0) > 0 else "down"
            },
            "timestamp": rating.get("created_at"),
        }
        assert interaction["interaction_data"]["vote"] == "up"

    def test_negative_rating_is_downvote(self):
        rating = {"user_id": "u1", "value": -1, "created_at": "2025-01-01"}
        interaction = {
            "user_id": rating.get("user_id"),
            "interaction_type": "vote",
            "interaction_data": {
                "vote": "up" if rating.get("value", 0) > 0 else "down"
            },
            "timestamp": rating.get("created_at"),
        }
        assert interaction["interaction_data"]["vote"] == "down"

    def test_zero_rating_is_downvote(self):
        """Zero value is not > 0, so it goes to 'down' branch."""
        rating = {"value": 0}
        vote = "up" if rating.get("value", 0) > 0 else "down"
        assert vote == "down"

    def test_multiple_ratings_to_interactions(self):
        ratings = [
            {"user_id": "u1", "value": 1, "created_at": "2025-01-01"},
            {"user_id": "u2", "value": -1, "created_at": "2025-01-02"},
        ]
        interactions = []
        for rating in ratings:
            interactions.append(
                {
                    "user_id": rating.get("user_id"),
                    "interaction_type": "vote",
                    "interaction_data": {
                        "vote": "up" if rating.get("value", 0) > 0 else "down"
                    },
                    "timestamp": rating.get("created_at"),
                }
            )
        assert len(interactions) == 2
        assert interactions[0]["interaction_data"]["vote"] == "up"
        assert interactions[1]["interaction_data"]["vote"] == "down"
