import json
from channels.generic.websocket import AsyncWebsocketConsumer
from channels.db import database_sync_to_async
from django.utils import timezone


class ChatConsumer(AsyncWebsocketConsumer):

    async def connect(self):
        self.room_slug = self.scope["url_route"]["kwargs"]["room_slug"]
        self.room_group_name = f"chat_{self.room_slug}"
        self.user = self.scope["user"]

        if not self.user or not self.user.is_authenticated:
            await self.close()
            return

        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )
        await self.accept()
        await self.update_last_seen()

        await self.channel_layer.group_send(
            self.room_group_name,
            {
                "type": "user_join",
                "username": self.user.username,
                "user_id": self.user.id,
            }
        )

    async def disconnect(self, close_code):
        if hasattr(self, "room_group_name"):
            await self.channel_layer.group_discard(
                self.room_group_name,
                self.channel_name
            )
            await self.update_last_seen()

    async def receive(self, text_data):
        data = json.loads(text_data)
        msg_type = data.get("type", "message")

        if msg_type == "message":
            content = data.get("content", "").strip()
            reply_to_id = data.get("reply_to")

            if not content:
                return

            message = await self.save_message(content, reply_to_id)
            if not message:
                return

            await self.channel_layer.group_send(
                self.room_group_name,
                {
                    "type": "chat_message",
                    "message_id": message["id"],
                    "content": content,
                    "sender_id": self.user.id,
                    "sender_username": self.user.username,
                    "sender_avatar": message["sender_avatar"],
                    "sender_neighborhood": message["sender_neighborhood"],
                    "reply_to": message["reply_to"],
                    "created_at": message["created_at"],
                }
            )

        elif msg_type == "typing":
            await self.channel_layer.group_send(
                self.room_group_name,
                {
                    "type": "typing_indicator",
                    "username": self.user.username,
                    "user_id": self.user.id,
                    "is_typing": data.get("is_typing", True),
                }
            )

        elif msg_type == "reaction":
            await self.handle_reaction(data)

    async def chat_message(self, event):
        await self.send(text_data=json.dumps({
            "type": "message",
            **event,
        }))

    async def typing_indicator(self, event):
        if event["user_id"] != self.user.id:
            await self.send(text_data=json.dumps({
                "type": "typing",
                **event,
            }))

    async def user_join(self, event):
        if event["user_id"] != self.user.id:
            await self.send(text_data=json.dumps({
                "type": "user_join",
                **event,
            }))

    @database_sync_to_async
    def save_message(self, content, reply_to_id=None):
        from chat.models import Message
        from community.models import Room

        try:
            room = Room.objects.get(slug=self.room_slug)
        except Room.DoesNotExist:
            return None

        reply_to = None
        reply_to_data = None
        if reply_to_id:
            try:
                reply_to = Message.objects.get(id=reply_to_id)
                reply_to_data = {
                    "id": reply_to.id,
                    "content": reply_to.content[:80],
                    "sender": reply_to.sender.username if reply_to.sender else "Unknown",
                }
            except Message.DoesNotExist:
                pass

        message = Message.objects.create(
            room=room,
            sender=self.user,
            content=content,
            reply_to=reply_to,
        )

        avatar_url = None
        if self.user.profile_image:
            avatar_url = self.user.profile_image.url

        return {
            "id": message.id,
            "sender_avatar": avatar_url,
            "sender_neighborhood": self.user.neighborhood or "",
            "reply_to": reply_to_data,
            "created_at": message.created_at.isoformat(),
        }

    @database_sync_to_async
    def update_last_seen(self):
        from account.models import User
        User.objects.filter(id=self.user.id).update(last_seen=timezone.now())

    @database_sync_to_async
    def handle_reaction(self, data):
        from chat.models import Message
        try:
            message = Message.objects.get(id=data["message_id"])
            emoji = data.get("emoji", "👍")
            user_id = str(self.user.id)
            reactions = message.reactions or {}

            if emoji not in reactions:
                reactions[emoji] = []

            if user_id in reactions[emoji]:
                reactions[emoji].remove(user_id)
                if not reactions[emoji]:
                    del reactions[emoji]
            else:
                reactions[emoji].append(user_id)

            message.reactions = reactions
            message.save(update_fields=["reactions"])
        except Message.DoesNotExist:
            pass