"""
Extended tests for news/rating_system/base_rater.py

Tests cover:
- RelevanceRating and QualityRating enum edge cases
- BaseRatingSystem abstract methods
- QualityRatingSystem rate() method
- RelevanceRatingSystem rate() method
- Rating validation edge cases
- _create_rating_record helper method
- get_recent_ratings default behavior
- get_card_ratings default behavior
- remove_rating default behavior
"""

import pytest
from unittest.mock import Mock
from datetime import datetime


class TestRelevanceRatingEnumExtended:
    """Extended tests for RelevanceRating enum."""

    def test_up_and_down_are_different(self):
        """UP and DOWN are distinct values."""
        from local_deep_research.news.rating_system.base_rater import (
            RelevanceRating,
        )

        assert RelevanceRating.UP != RelevanceRating.DOWN

    def test_can_compare_by_value(self):
        """Can compare enum values."""
        from local_deep_research.news.rating_system.base_rater import (
            RelevanceRating,
        )

        assert RelevanceRating.UP.value == "up"
        assert RelevanceRating("up") == RelevanceRating.UP

    def test_can_create_from_string_value(self):
        """Can create enum from string value."""
        from local_deep_research.news.rating_system.base_rater import (
            RelevanceRating,
        )

        assert RelevanceRating("down") == RelevanceRating.DOWN

    def test_invalid_value_raises_error(self):
        """Invalid value raises ValueError."""
        from local_deep_research.news.rating_system.base_rater import (
            RelevanceRating,
        )

        with pytest.raises(ValueError):
            RelevanceRating("invalid")

    def test_name_property(self):
        """Name property returns enum name."""
        from local_deep_research.news.rating_system.base_rater import (
            RelevanceRating,
        )

        assert RelevanceRating.UP.name == "UP"
        assert RelevanceRating.DOWN.name == "DOWN"


class TestQualityRatingEnumExtended:
    """Extended tests for QualityRating enum."""

    def test_sequential_values(self):
        """Values are sequential 1-5."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRating,
        )

        values = [r.value for r in QualityRating]
        assert values == [1, 2, 3, 4, 5]

    def test_can_create_from_int(self):
        """Can create enum from integer value."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRating,
        )

        assert QualityRating(3) == QualityRating.THREE_STARS

    def test_invalid_value_raises_error(self):
        """Invalid value raises ValueError."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRating,
        )

        with pytest.raises(ValueError):
            QualityRating(0)

        with pytest.raises(ValueError):
            QualityRating(6)

    def test_two_stars_value(self):
        """TWO_STARS has value 2."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRating,
        )

        assert QualityRating.TWO_STARS.value == 2

    def test_three_stars_value(self):
        """THREE_STARS has value 3."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRating,
        )

        assert QualityRating.THREE_STARS.value == 3

    def test_four_stars_value(self):
        """FOUR_STARS has value 4."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRating,
        )

        assert QualityRating.FOUR_STARS.value == 4

    def test_name_property(self):
        """Name property returns enum name."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRating,
        )

        assert QualityRating.ONE_STAR.name == "ONE_STAR"
        assert QualityRating.FIVE_STARS.name == "FIVE_STARS"


class TestBaseRatingSystemValidation:
    """Tests for BaseRatingSystem validation methods."""

    def test_validate_rating_value_rejects_none(self):
        """_validate_rating_value rejects None."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
        )

        system = QualityRatingSystem()

        with pytest.raises(ValueError, match="cannot be None"):
            system._validate_rating_value(None)

    def test_quality_system_rejects_integer_rating(self):
        """QualityRatingSystem rejects raw integer."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
        )

        system = QualityRatingSystem()

        with pytest.raises(ValueError, match="QualityRating enum value"):
            system._validate_rating_value(5)

    def test_quality_system_rejects_string_rating(self):
        """QualityRatingSystem rejects string."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
        )

        system = QualityRatingSystem()

        with pytest.raises(ValueError, match="QualityRating enum value"):
            system._validate_rating_value("five stars")

    def test_relevance_system_rejects_string_rating(self):
        """RelevanceRatingSystem rejects string."""
        from local_deep_research.news.rating_system.base_rater import (
            RelevanceRatingSystem,
        )

        system = RelevanceRatingSystem()

        with pytest.raises(ValueError, match="RelevanceRating"):
            system._validate_rating_value("up")

    def test_relevance_system_rejects_boolean_rating(self):
        """RelevanceRatingSystem rejects boolean."""
        from local_deep_research.news.rating_system.base_rater import (
            RelevanceRatingSystem,
        )

        system = RelevanceRatingSystem()

        with pytest.raises(ValueError, match="RelevanceRating"):
            system._validate_rating_value(True)


class TestQualityRatingSystemRate:
    """Tests for QualityRatingSystem.rate() method."""

    def test_rate_returns_success_dict(self):
        """rate() returns success dict."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
            QualityRating,
        )

        system = QualityRatingSystem()
        result = system.rate("user1", "card1", QualityRating.FOUR_STARS)

        assert result["success"] is True

    def test_rate_includes_rating_record(self):
        """rate() includes rating record in response."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
            QualityRating,
        )

        system = QualityRatingSystem()
        result = system.rate("user1", "card1", QualityRating.THREE_STARS)

        assert "rating" in result
        assert result["rating"]["user_id"] == "user1"
        assert result["rating"]["card_id"] == "card1"

    def test_rate_includes_message(self):
        """rate() includes message in response."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
            QualityRating,
        )

        system = QualityRatingSystem()
        result = system.rate("user1", "card1", QualityRating.FIVE_STARS)

        assert "message" in result
        assert "5 stars" in result["message"]

    def test_rate_records_rating_type(self):
        """rate() records correct rating type."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
            QualityRating,
        )

        system = QualityRatingSystem()
        result = system.rate("user1", "card1", QualityRating.TWO_STARS)

        assert result["rating"]["rating_type"] == "quality"

    def test_rate_records_rating_value(self):
        """rate() records rating value."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
            QualityRating,
        )

        system = QualityRatingSystem()
        result = system.rate("user1", "card1", QualityRating.ONE_STAR)

        assert result["rating"]["rating_value"] == QualityRating.ONE_STAR

    def test_rate_includes_timestamp(self):
        """rate() includes rated_at timestamp."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
            QualityRating,
        )

        system = QualityRatingSystem()
        result = system.rate("user1", "card1", QualityRating.FOUR_STARS)

        assert "rated_at" in result["rating"]
        # Should be ISO format
        datetime.fromisoformat(
            result["rating"]["rated_at"].replace("Z", "+00:00")
        )

    def test_rate_with_metadata(self):
        """rate() accepts and stores metadata."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
            QualityRating,
        )

        system = QualityRatingSystem()
        metadata = {"source": "manual", "comment": "great article"}
        result = system.rate(
            "user1", "card1", QualityRating.FIVE_STARS, metadata=metadata
        )

        assert result["rating"]["metadata"] == metadata

    def test_rate_empty_metadata_by_default(self):
        """rate() has empty metadata by default."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
            QualityRating,
        )

        system = QualityRatingSystem()
        result = system.rate("user1", "card1", QualityRating.THREE_STARS)

        assert result["rating"]["metadata"] == {}


class TestRelevanceRatingSystemRate:
    """Tests for RelevanceRatingSystem.rate() method."""

    def test_rate_up_returns_success(self):
        """rate() with UP returns success."""
        from local_deep_research.news.rating_system.base_rater import (
            RelevanceRatingSystem,
            RelevanceRating,
        )

        system = RelevanceRatingSystem()
        result = system.rate("user1", "card1", RelevanceRating.UP)

        assert result["success"] is True

    def test_rate_down_returns_success(self):
        """rate() with DOWN returns success."""
        from local_deep_research.news.rating_system.base_rater import (
            RelevanceRatingSystem,
            RelevanceRating,
        )

        system = RelevanceRatingSystem()
        result = system.rate("user1", "card1", RelevanceRating.DOWN)

        assert result["success"] is True

    def test_rate_message_indicates_direction(self):
        """rate() message indicates thumbs direction."""
        from local_deep_research.news.rating_system.base_rater import (
            RelevanceRatingSystem,
            RelevanceRating,
        )

        system = RelevanceRatingSystem()

        up_result = system.rate("user1", "card1", RelevanceRating.UP)
        assert "thumbs up" in up_result["message"]

        down_result = system.rate("user1", "card2", RelevanceRating.DOWN)
        assert "thumbs down" in down_result["message"]

    def test_rate_records_rating_type(self):
        """rate() records correct rating type."""
        from local_deep_research.news.rating_system.base_rater import (
            RelevanceRatingSystem,
            RelevanceRating,
        )

        system = RelevanceRatingSystem()
        result = system.rate("user1", "card1", RelevanceRating.UP)

        assert result["rating"]["rating_type"] == "relevance"

    def test_rate_records_rating_value(self):
        """rate() records rating value enum."""
        from local_deep_research.news.rating_system.base_rater import (
            RelevanceRatingSystem,
            RelevanceRating,
        )

        system = RelevanceRatingSystem()
        result = system.rate("user1", "card1", RelevanceRating.DOWN)

        assert result["rating"]["rating_value"] == RelevanceRating.DOWN


class TestRatingSystemGetMethods:
    """Tests for rating system get methods."""

    def test_quality_get_rating_without_storage_returns_none(self):
        """get_rating() without storage returns None."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
        )

        system = QualityRatingSystem()
        result = system.get_rating("user1", "card1")

        assert result is None

    def test_relevance_get_rating_without_storage_returns_none(self):
        """get_rating() without storage returns None."""
        from local_deep_research.news.rating_system.base_rater import (
            RelevanceRatingSystem,
        )

        system = RelevanceRatingSystem()
        result = system.get_rating("user1", "card1")

        assert result is None

    def test_get_recent_ratings_returns_empty_list(self):
        """get_recent_ratings() returns empty list by default."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
        )

        system = QualityRatingSystem()
        result = system.get_recent_ratings("user1")

        assert result == []

    def test_get_recent_ratings_respects_limit(self):
        """get_recent_ratings() accepts limit parameter."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
        )

        system = QualityRatingSystem()
        # Should not raise even with different limit
        result = system.get_recent_ratings("user1", limit=100)

        assert result == []

    def test_get_card_ratings_returns_default_dict(self):
        """get_card_ratings() returns default dict."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
        )

        system = QualityRatingSystem()
        result = system.get_card_ratings("card1")

        assert result == {"total": 0, "average": None}


class TestRatingSystemRemoveRating:
    """Tests for remove_rating method."""

    def test_remove_rating_returns_false_without_storage(self):
        """remove_rating() returns False without storage."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
        )

        system = QualityRatingSystem()
        result = system.remove_rating("user1", "card1")

        assert result is False


class TestRatingSystemStorageBackend:
    """Tests for storage backend integration."""

    def test_quality_system_stores_backend(self):
        """QualityRatingSystem stores backend."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
        )

        mock_storage = Mock()
        system = QualityRatingSystem(storage_backend=mock_storage)

        assert system.storage_backend is mock_storage

    def test_relevance_system_stores_backend(self):
        """RelevanceRatingSystem stores backend."""
        from local_deep_research.news.rating_system.base_rater import (
            RelevanceRatingSystem,
        )

        mock_storage = Mock()
        system = RelevanceRatingSystem(storage_backend=mock_storage)

        assert system.storage_backend is mock_storage

    def test_rating_type_attribute(self):
        """Rating type attribute is set from class name."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
        )

        system = QualityRatingSystem()

        assert system.rating_type == "QualityRatingSystem"


class TestGetRatingType:
    """Tests for get_rating_type method."""

    def test_quality_rating_type(self):
        """QualityRatingSystem returns 'quality'."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
        )

        system = QualityRatingSystem()
        assert system.get_rating_type() == "quality"

    def test_relevance_rating_type(self):
        """RelevanceRatingSystem returns 'relevance'."""
        from local_deep_research.news.rating_system.base_rater import (
            RelevanceRatingSystem,
        )

        system = RelevanceRatingSystem()
        assert system.get_rating_type() == "relevance"


class TestRatingRecordCreation:
    """Tests for _create_rating_record helper."""

    def test_includes_all_required_fields(self):
        """Rating record has all required fields."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
            QualityRating,
        )

        system = QualityRatingSystem()
        record = system._create_rating_record(
            "user1", "card1", QualityRating.FIVE_STARS
        )

        assert "user_id" in record
        assert "card_id" in record
        assert "rating_type" in record
        assert "rating_value" in record
        assert "rated_at" in record
        assert "metadata" in record

    def test_record_has_correct_user_id(self):
        """Rating record has correct user_id."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
            QualityRating,
        )

        system = QualityRatingSystem()
        record = system._create_rating_record(
            "test_user_123", "card1", QualityRating.THREE_STARS
        )

        assert record["user_id"] == "test_user_123"

    def test_record_has_correct_card_id(self):
        """Rating record has correct card_id."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
            QualityRating,
        )

        system = QualityRatingSystem()
        record = system._create_rating_record(
            "user1", "card_abc_123", QualityRating.FOUR_STARS
        )

        assert record["card_id"] == "card_abc_123"

    def test_rated_at_is_iso_format(self):
        """rated_at is in ISO format."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
            QualityRating,
        )

        system = QualityRatingSystem()
        record = system._create_rating_record(
            "user1", "card1", QualityRating.ONE_STAR
        )

        # Should parse without error
        from datetime import datetime

        datetime.fromisoformat(record["rated_at"].replace("Z", "+00:00"))

    def test_metadata_defaults_to_empty_dict(self):
        """Metadata defaults to empty dict when not provided."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
            QualityRating,
        )

        system = QualityRatingSystem()
        record = system._create_rating_record(
            "user1", "card1", QualityRating.TWO_STARS
        )

        assert record["metadata"] == {}

    def test_metadata_is_passed_through(self):
        """Custom metadata is included in record."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
            QualityRating,
        )

        system = QualityRatingSystem()
        custom_meta = {"source": "api", "version": "1.0"}
        record = system._create_rating_record(
            "user1", "card1", QualityRating.FIVE_STARS, metadata=custom_meta
        )

        assert record["metadata"] == custom_meta


class TestRatingSystemMultipleRatings:
    """Tests for multiple rating scenarios."""

    def test_different_users_can_rate_same_card(self):
        """Different users can rate the same card."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
            QualityRating,
        )

        system = QualityRatingSystem()

        result1 = system.rate("user1", "shared_card", QualityRating.FIVE_STARS)
        result2 = system.rate("user2", "shared_card", QualityRating.THREE_STARS)

        assert result1["success"] is True
        assert result2["success"] is True
        assert result1["rating"]["user_id"] == "user1"
        assert result2["rating"]["user_id"] == "user2"

    def test_same_user_can_rate_different_cards(self):
        """Same user can rate different cards."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
            QualityRating,
        )

        system = QualityRatingSystem()

        result1 = system.rate("user1", "card1", QualityRating.FOUR_STARS)
        result2 = system.rate("user1", "card2", QualityRating.TWO_STARS)
        result3 = system.rate("user1", "card3", QualityRating.FIVE_STARS)

        assert all([result1["success"], result2["success"], result3["success"]])

    def test_relevance_rating_after_quality_rating(self):
        """Can rate both quality and relevance for same card."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRatingSystem,
            RelevanceRatingSystem,
            QualityRating,
            RelevanceRating,
        )

        quality_system = QualityRatingSystem()
        relevance_system = RelevanceRatingSystem()

        quality_result = quality_system.rate(
            "user1", "card1", QualityRating.FOUR_STARS
        )
        relevance_result = relevance_system.rate(
            "user1", "card1", RelevanceRating.UP
        )

        assert quality_result["success"] is True
        assert relevance_result["success"] is True
        assert quality_result["rating"]["rating_type"] == "quality"
        assert relevance_result["rating"]["rating_type"] == "relevance"


class TestRatingEnumComparisons:
    """Tests for rating enum comparisons."""

    def test_quality_ratings_comparable(self):
        """Quality rating values are comparable."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRating,
        )

        assert QualityRating.ONE_STAR.value < QualityRating.FIVE_STARS.value
        assert QualityRating.THREE_STARS.value > QualityRating.TWO_STARS.value

    def test_quality_ratings_can_be_sorted(self):
        """Quality ratings can be sorted by value."""
        from local_deep_research.news.rating_system.base_rater import (
            QualityRating,
        )

        ratings = [
            QualityRating.FIVE_STARS,
            QualityRating.ONE_STAR,
            QualityRating.THREE_STARS,
        ]
        sorted_ratings = sorted(ratings, key=lambda r: r.value)

        assert sorted_ratings[0] == QualityRating.ONE_STAR
        assert sorted_ratings[-1] == QualityRating.FIVE_STARS

    def test_relevance_rating_equality(self):
        """Relevance ratings support equality comparison."""
        from local_deep_research.news.rating_system.base_rater import (
            RelevanceRating,
        )

        up1 = RelevanceRating.UP
        up2 = RelevanceRating("up")

        assert up1 == up2
