import json
from channels.generic.websocket import AsyncWebsocketConsumer
from channels.db import database_sync_to_async
from .models import Room, Message
from django.contrib.auth.models import User

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = f'chat_{self.room_name}'

        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )

        await self.accept()

    async def disconnect(self, close_code):
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )

    async def receive(self, text_data):
        data = json.loads(text_data)
        msg_type = data.get('type', 'chat_message') # تشخیص نوع پیام (متن یا سین)
        user_id = data.get('user_id')

        # --- ۱. اگر پیام جدید متنی بود ---
        if msg_type == 'chat_message':
            message = data['message']
            
            if user_id:
                # ذخیره پیام و دریافت اطلاعات فرستنده
                user_info = await self.save_message(user_id, self.room_name, message)

                if user_info:
                    # ارسال به گروه
                    await self.channel_layer.group_send(
                        self.room_group_name,
                        {
                            'type': 'chat_message',
                            'message': message,
                            'user_id': user_id,
                            'username': user_info['name'],
                            'user_avatar': user_info['avatar'],
                            'is_read': False,
                        }
                    )

                    # 2. ارسال نوتیفیکیشن به گیرنده
                    # گیرنده کیست؟ کسی که آیدیش در user_id (فرستنده) نیست ولی عضو اتاق است.
                    # اما اینجا ما room_name را داریم: private_A_B
                    # اگر private باشد، گیرنده را پیدا می‌کنیم
                    if 'private_' in self.room_name:
                        ids = self.room_name.replace('private_', '').split('_')
                        # پیدا کردن آیدی گیرنده (کسی که فرستنده نیست)
                        receiver_id = ids[0] if str(ids[0]) != str(user_id) else ids[1]
                        
                        await self.channel_layer.group_send(
                            f"notify_user_{receiver_id}", # اسم گروه نوتیفیکیشن گیرنده
                            {
                                'type': 'send_notification',
                                'message_type': 'new_message',
                                'sender_id': user_id,
                                'sender_name': user_info['name']
                            }
                        )

        # --- ۲. اگر اعلام "سین شدن" بود ---
        elif msg_type == 'mark_read':
            if user_id:
                # پیام‌های طرف مقابل را در دیتابیس "خوانده شده" کن
                await self.mark_messages_as_read(user_id, self.room_name)
                
                # به گروه خبر بده که این کاربر پیام‌ها را خواند
                await self.channel_layer.group_send(
                    self.room_group_name,
                    {
                        'type': 'read_receipt',
                        'reader_id': user_id
                    }
                )

    # --- هندلر ارسال پیام به کلاینت ---
    async def chat_message(self, event):
        await self.send(text_data=json.dumps({
            'type': 'chat_message',
            'message': event['message'],
            'user_id': event['user_id'],
            'username': event['username'],
            'user_avatar': event.get('user_avatar'),
            'image': event.get('image'),
            'is_read': event['is_read'],
        }))

    # --- هندلر ارسال وضعیت سین به کلاینت ---
    async def read_receipt(self, event):
        await self.send(text_data=json.dumps({
            'type': 'read_receipt',
            'reader_id': event['reader_id']
        }))

    # متدهای دیتابیس
    @database_sync_to_async
    def save_message(self, user_id, room_name, message):
        try:
            user = User.objects.get(id=user_id)
            room, created = Room.objects.get_or_create(name=room_name)
            
            if created:
                if room_name == 'general':
                    room.room_type = 'public'
                else:
                    room.room_type = 'private'
                room.save()
            
            Message.objects.create(sender=user, room=room, content=message)
            
            # دریافت آواتار
            avatar_url = None
            try:
                if hasattr(user, 'profile') and user.profile.avatar:
                    avatar_url = user.profile.avatar.url
            except:
                pass
            
            return {
                'name': user.get_full_name() or user.username,
                'avatar': avatar_url
            }
        except Exception as e:
            print(f"Error saving message: {e}")
            return None

    @database_sync_to_async
    def mark_messages_as_read(self, user_id, room_name):
        try:
            room = Room.objects.get(name=room_name)
            # تمام پیام‌هایی که خوانده نشده‌اند و فرستنده‌اش "من نیستم" را آپدیت کن
            # (یعنی پیام‌های طرف مقابل را سین کردم)
            room.messages.filter(is_read=False).exclude(sender_id=user_id).update(is_read=True)
        except Exception as e:
            print(f"Error marking messages read: {e}")


class NotificationConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.group_name = None
        
        if self.scope["user"].is_anonymous:
            await self.close()
        else:
            self.group_name = f"notify_user_{self.scope['user'].id}"
            await self.channel_layer.group_add(self.group_name, self.channel_name)
            await self.accept()

    async def disconnect(self, close_code):
        if self.group_name:
            await self.channel_layer.group_discard(self.group_name, self.channel_name)
    
    async def send_notification(self, event):
        await self.send(text_data=json.dumps(event))