"""My-Sea spectate WebSocket — pushes the owner's draw to watching invitees so
they witness each card land WITHOUT refreshing (user-spec 2026-05-29).

Mirrors the epic `RoomConsumer` broadcast pattern (view → `group_send` →
consumer handler → `send_json`), but keyed on the owner (`mysea_<owner_id>`)
since my-sea has no Room. Read-only: clients never send, they only receive
events — `sea_draw` (the owner's full current hand + spread), `sea_spread` (a
spread change on modal-close, no hand), and `sea_seats` (the presence ring);
`my-sea-seats.js` / sea.js apply them to the cross + hex. Membership gate matches
the voice consumer — the owner, or a present invitee (deposited, not left).
"""

from channels.db import database_sync_to_async
from channels.generic.websocket import AsyncJsonWebsocketConsumer


class MySeaSpectateConsumer(AsyncJsonWebsocketConsumer):
    async def connect(self):
        self.owner_id = self.scope["url_route"]["kwargs"]["owner_id"]
        self.user = self.scope.get("user")
        self.group = None
        if not (self.user and getattr(self.user, "is_authenticated", False)):
            await self.close()
            return
        if not await self._can_watch():
            await self.close()
            return
        self.group = f"mysea_{self.owner_id}"
        await self.channel_layer.group_add(self.group, self.channel_name)
        await self.accept()

    async def disconnect(self, code):
        if self.group:
            await self.channel_layer.group_discard(self.group, self.channel_name)

    # ── room-group fan-out handlers ─────────────────────────────────────
    async def sea_draw(self, event):
        """Relay the owner's hand (+ current spread) to the watching client. The
        spread lets a spectator re-sync its cross layout/captions if the owner
        switched spreads (post-DEL) since the page loaded."""
        await self.send_json({
            "type": "sea_draw",
            "hand": event.get("hand", []),
            "spread": event.get("spread", ""),
        })

    async def sea_seats(self, event):
        """Relay the seat ring (a deposit took / a BYE freed a seat)."""
        await self.send_json({"type": "sea_seats", "seats": event.get("seats", [])})

    async def sea_spread(self, event):
        """Relay a spread change the moment the owner closes her SPREAD modal, so
        the spectator re-lays-out BEFORE any card lands (no hand in this event)."""
        await self.send_json({"type": "sea_spread", "spread": event.get("spread", "")})

    # ── membership gate ─────────────────────────────────────────────────
    @database_sync_to_async
    def _can_watch(self):
        """The owner OR a present invitee (ACCEPTED + deposited + not left)."""
        if str(self.user.id) == str(self.owner_id):
            return True
        from apps.gameboard.models import SeaInvite
        return SeaInvite.objects.filter(
            owner_id=self.owner_id, invitee=self.user,
            status=SeaInvite.ACCEPTED,
            token_deposited_at__isnull=False, left_at__isnull=True,
        ).exists()
