"""
Tests for Core managers and querysets.

Following Django styleguide pattern: test__<context>__<action>__<expected_outcome>
"""

import pytest
from django.test import TestCase

from tests.factories import (
    ParkFactory,
    ParkReviewFactory,
    UserFactory,
)


@pytest.mark.django_db
class TestBaseQuerySet(TestCase):
    """Tests for BaseQuerySet."""

    def test__active__filters_active_records(self):
        """Test active filters by is_active field if present."""
        # Using User model which has is_active
        from django.contrib.auth import get_user_model

        User = get_user_model()

        active_user = User.objects.create_user(
            username="active", email="active@test.com", password="test", is_active=True
        )
        inactive_user = User.objects.create_user(
            username="inactive", email="inactive@test.com", password="test", is_active=False
        )

        result = User.objects.filter(is_active=True)

        assert active_user in result
        assert inactive_user not in result

    def test__recent__filters_recently_created(self):
        """Test recent filters by created_at within days."""
        park = ParkFactory()
        # Created just now, should be in recent

        from apps.parks.models import Park

        result = Park.objects.recent(days=30)

        assert park in result

    def test__search__searches_by_name(self):
        """Test search filters by name field."""
        park1 = ParkFactory(name="Cedar Point")
        park2 = ParkFactory(name="Kings Island")

        from apps.parks.models import Park

        result = Park.objects.search(query="Cedar")

        assert park1 in result
        assert park2 not in result

    def test__search__empty_query__returns_all(self):
        """Test search with empty query returns all records."""
        park1 = ParkFactory()
        park2 = ParkFactory()

        from apps.parks.models import Park

        result = Park.objects.search(query="")

        assert park1 in result
        assert park2 in result


@pytest.mark.django_db
class TestLocationQuerySet(TestCase):
    """Tests for LocationQuerySet."""

    def test__by_country__filters_by_country(self):
        """Test by_country filters by country field."""
        # Create parks with locations through factory
        us_park = ParkFactory()
        # Location is created by factory post_generation

        from apps.parks.models import Park

        # This tests the pattern - actual filtering depends on location setup

        result = Park.objects.all()
        assert us_park in result


@pytest.mark.django_db
class TestReviewableQuerySet(TestCase):
    """Tests for ReviewableQuerySet."""

    def test__with_review_stats__annotates_review_count(self):
        """Test with_review_stats adds review count annotation."""
        from apps.parks.models import Park

        park = ParkFactory()
        user1 = UserFactory()
        user2 = UserFactory()
        ParkReviewFactory(park=park, user=user1, is_published=True)
        ParkReviewFactory(park=park, user=user2, is_published=True)

        result = Park.objects.with_review_stats().get(pk=park.pk)

        assert result.review_count == 2

    def test__with_review_stats__calculates_average_rating(self):
        """Test with_review_stats calculates average rating."""
        from apps.parks.models import Park

        park = ParkFactory()
        user1 = UserFactory()
        user2 = UserFactory()
        ParkReviewFactory(park=park, user=user1, is_published=True, rating=8)
        ParkReviewFactory(park=park, user=user2, is_published=True, rating=10)

        result = Park.objects.with_review_stats().get(pk=park.pk)

        assert result.average_rating == 9.0

    def test__with_review_stats__excludes_unpublished(self):
        """Test with_review_stats excludes unpublished reviews."""
        from apps.parks.models import Park

        park = ParkFactory()
        user1 = UserFactory()
        user2 = UserFactory()
        ParkReviewFactory(park=park, user=user1, is_published=True, rating=10)
        ParkReviewFactory(park=park, user=user2, is_published=False, rating=2)

        result = Park.objects.with_review_stats().get(pk=park.pk)

        assert result.review_count == 1
        assert result.average_rating == 10.0

    def test__highly_rated__filters_by_minimum_rating(self):
        """Test highly_rated filters by minimum average rating."""
        from apps.parks.models import Park

        high_rated = ParkFactory()
        low_rated = ParkFactory()

        user1 = UserFactory()
        user2 = UserFactory()
        ParkReviewFactory(park=high_rated, user=user1, is_published=True, rating=9)
        ParkReviewFactory(park=low_rated, user=user2, is_published=True, rating=4)

        result = Park.objects.highly_rated(min_rating=8.0)

        assert high_rated in result
        assert low_rated not in result

    def test__recently_reviewed__filters_by_recent_reviews(self):
        """Test recently_reviewed filters parks with recent reviews."""
        from apps.parks.models import Park

        reviewed_park = ParkFactory()
        user = UserFactory()
        ParkReviewFactory(park=reviewed_park, user=user, is_published=True)

        result = Park.objects.get_queryset().recently_reviewed(days=30)

        assert reviewed_park in result


@pytest.mark.django_db
class TestStatusQuerySet(TestCase):
    """Tests for StatusQuerySet."""

    def test__with_status__single_status__filters_correctly(self):
        """Test with_status filters by single status."""
        from apps.parks.models import Park

        operating = ParkFactory(status="OPERATING")
        closed = ParkFactory(status="CLOSED_PERM")

        result = Park.objects.get_queryset().with_status(status="OPERATING")

        assert operating in result
        assert closed not in result

    def test__with_status__multiple_statuses__filters_correctly(self):
        """Test with_status filters by multiple statuses."""
        from apps.parks.models import Park

        operating = ParkFactory(status="OPERATING")
        closed_temp = ParkFactory(status="CLOSED_TEMP")
        closed_perm = ParkFactory(status="CLOSED_PERM")

        result = Park.objects.get_queryset().with_status(status=["CLOSED_TEMP", "CLOSED_PERM"])

        assert operating not in result
        assert closed_temp in result
        assert closed_perm in result

    def test__operating__filters_operating_status(self):
        """Test operating filters for OPERATING status."""
        from apps.parks.models import Park

        operating = ParkFactory(status="OPERATING")
        closed = ParkFactory(status="CLOSED_PERM")

        result = Park.objects.operating()

        assert operating in result
        assert closed not in result

    def test__closed__filters_closed_statuses(self):
        """Test closed filters for closed statuses."""
        from apps.parks.models import Park

        operating = ParkFactory(status="OPERATING")
        closed_temp = ParkFactory(status="CLOSED_TEMP")
        closed_perm = ParkFactory(status="CLOSED_PERM")

        result = Park.objects.closed()

        assert operating not in result
        assert closed_temp in result
        assert closed_perm in result


@pytest.mark.django_db
class TestTimestampedQuerySet(TestCase):
    """Tests for TimestampedQuerySet."""

    def test__by_creation_date_descending__orders_newest_first(self):
        """Test by_creation_date with descending orders newest first."""
        from apps.parks.models import Park

        park1 = ParkFactory()
        park2 = ParkFactory()

        result = list(Park.objects.get_queryset().by_creation_date(descending=True))

        # Most recently created should be first
        assert result[0] == park2
        assert result[1] == park1

    def test__by_creation_date_ascending__orders_oldest_first(self):
        """Test by_creation_date with ascending orders oldest first."""
        from apps.parks.models import Park

        park1 = ParkFactory()
        park2 = ParkFactory()

        result = list(Park.objects.get_queryset().by_creation_date(descending=False))

        # Oldest should be first
        assert result[0] == park1
        assert result[1] == park2


@pytest.mark.django_db
class TestBaseManager(TestCase):
    """Tests for BaseManager."""

    def test__active__delegates_to_queryset(self):
        """Test active method delegates to queryset."""
        from django.contrib.auth import get_user_model

        User = get_user_model()

        user = User.objects.create_user(username="test", email="test@test.com", password="test", is_active=True)

        # BaseManager's active method should work
        result = User.objects.filter(is_active=True)
        assert user in result

    def test__recent__delegates_to_queryset(self):
        """Test recent method delegates to queryset."""
        from apps.parks.models import Park

        park = ParkFactory()

        result = Park.objects.recent(days=30)
        assert park in result

    def test__search__delegates_to_queryset(self):
        """Test search method delegates to queryset."""
        from apps.parks.models import Park

        park = ParkFactory(name="Unique Name")

        result = Park.objects.search(query="Unique")
        assert park in result


@pytest.mark.django_db
class TestStatusManager(TestCase):
    """Tests for StatusManager."""

    def test__operating__delegates_to_queryset(self):
        """Test operating method delegates to queryset."""
        from apps.parks.models import Park

        operating = ParkFactory(status="OPERATING")

        result = Park.objects.operating()
        assert operating in result

    def test__closed__delegates_to_queryset(self):
        """Test closed method delegates to queryset."""
        from apps.parks.models import Park

        closed = ParkFactory(status="CLOSED_PERM")

        result = Park.objects.closed()
        assert closed in result


@pytest.mark.django_db
class TestReviewableManager(TestCase):
    """Tests for ReviewableManager."""

    def test__with_review_stats__delegates_to_queryset(self):
        """Test with_review_stats method delegates to queryset."""
        from apps.parks.models import Park

        park = ParkFactory()

        result = Park.objects.with_review_stats()
        assert park in result

    def test__highly_rated__delegates_to_queryset(self):
        """Test highly_rated method delegates to queryset."""
        from apps.parks.models import Park

        park = ParkFactory()
        user = UserFactory()
        ParkReviewFactory(park=park, user=user, is_published=True, rating=9)

        result = Park.objects.highly_rated(min_rating=8.0)
        assert park in result
