from datetime import timedelta
from unittest.mock import MagicMock

from django.test import TestCase, RequestFactory
from django.utils import timezone

from apps.drama.models import GameEvent, record
from apps.epic.models import Room
from apps.lyric.models import User

from core.context_processors import navbar_context


class NavbarContextProcessorTest(TestCase):
    def setUp(self):
        self.factory = RequestFactory()

    def _anon_request(self):
        req = self.factory.get("/")
        req.user = MagicMock(is_authenticated=False)
        return req

    def _auth_request(self, user):
        req = self.factory.get("/")
        req.user = user
        return req

    def _room_with_event(self, owner, name="Test Room"):
        room = Room.objects.create(name=name, owner=owner)
        record(
            room, GameEvent.SLOT_FILLED, actor=owner,
            slot_number=1, token_type="coin",
            token_display="Coin-on-a-String", renewal_days=7,
        )
        return room

    # ------------------------------------------------------------------ #
    # Anonymous user                                                       #
    # ------------------------------------------------------------------ #

    def test_returns_empty_for_anonymous_user(self):
        ctx = navbar_context(self._anon_request())
        self.assertEqual(ctx, {})

    # ------------------------------------------------------------------ #
    # Authenticated user — no rooms                                        #
    # ------------------------------------------------------------------ #

    def test_returns_empty_when_no_rooms_with_events(self):
        user = User.objects.create(email="disco@test.io")
        # Room exists but has no events
        Room.objects.create(name="Empty Room", owner=user)

        ctx = navbar_context(self._auth_request(user))
        self.assertEqual(ctx, {})

    # ------------------------------------------------------------------ #
    # Room in gate phase (no table_status) → gatekeeper URL               #
    # ------------------------------------------------------------------ #

    def test_returns_gatekeeper_url_for_gate_phase_room(self):
        user = User.objects.create(email="disco@test.io")
        room = self._room_with_event(user)

        ctx = navbar_context(self._auth_request(user))
        self.assertIn("navbar_recent_room_url", ctx)
        self.assertIn(str(room.id), ctx["navbar_recent_room_url"])
        self.assertIn("gate", ctx["navbar_recent_room_url"])

    # ------------------------------------------------------------------ #
    # Room in role-select (table_status set) → room view URL              #
    # ------------------------------------------------------------------ #

    def test_returns_room_url_for_table_status_room(self):
        user = User.objects.create(email="disco@test.io")
        room = self._room_with_event(user)
        room.table_status = Room.ROLE_SELECT
        room.save()

        ctx = navbar_context(self._auth_request(user))
        self.assertIn("navbar_recent_room_url", ctx)
        self.assertIn(str(room.id), ctx["navbar_recent_room_url"])
        self.assertNotIn("gate", ctx["navbar_recent_room_url"])

    # ------------------------------------------------------------------ #
    # Most recently updated room is chosen                                 #
    # ------------------------------------------------------------------ #

    def test_returns_most_recently_updated_room(self):
        user = User.objects.create(email="disco@test.io")
        older_room = self._room_with_event(user, name="Older Room")
        newer_room = self._room_with_event(user, name="Newer Room")

        ctx = navbar_context(self._auth_request(user))
        self.assertIn(str(newer_room.id), ctx["navbar_recent_room_url"])
        self.assertNotIn(str(older_room.id), ctx["navbar_recent_room_url"])

    # ------------------------------------------------------------------ #
    # User sees own rooms but not others' rooms they never joined         #
    # ------------------------------------------------------------------ #

    def test_ignores_rooms_user_has_no_connection_to(self):
        owner = User.objects.create(email="owner@test.io")
        other = User.objects.create(email="other@test.io")
        # Create a room belonging only to `owner`
        self._room_with_event(owner)

        ctx = navbar_context(self._auth_request(other))
        self.assertEqual(ctx, {})
