import uuid
from django.db import models
from django.utils import timezone
from django.core.validators import MinValueValidator, MaxValueValidator
from django.conf import settings
import base64
import hashlib

class ChatRoom(models.Model):
    """Enhanced chat room with academic integration"""
    
    ROOM_TYPES = [
        ('INDIVIDUAL', 'Individual'),
        ('GROUP', 'Group'),
        ('CLASS', 'Class'),  # Whole class group
        ('SUBJECT', 'Subject'),  # Subject-specific group
        ('PARENT_TEACHER', 'Parent-Teacher'),
        ('STUDENT_GROUP', 'Student Group'),
        ('TEACHER_GROUP', 'Teacher Group'),
    ]
    
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    room_type = models.CharField(max_length=20, choices=ROOM_TYPES, default='INDIVIDUAL')
    name = models.CharField(max_length=255, null=True, blank=True, help_text="For group chats")
    description = models.TextField(blank=True, null=True)
    
    # Academic relationships (for academic groups)
    academic_class = models.ForeignKey(
        'academics.AcademicClass',
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='chat_rooms'
    )
    subject = models.ForeignKey(
        'academics.Subject',
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='chat_rooms'
    )
    subject_group = models.ForeignKey(
        'academics.SubjectGroup',
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='chat_rooms'
    )
    academic_year = models.ForeignKey(
        'academics.AcademicYear',
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='chat_rooms'
    )
    
    # Participants (using through model)
    teachers = models.ManyToManyField(
        'people.Teacher', 
        through='ChatParticipantTeacher',
        related_name='chat_rooms', 
        blank=True
    )
    parents = models.ManyToManyField(
        'people.Parent', 
        through='ChatParticipantParent',
        related_name='chat_rooms', 
        blank=True
    )
    students = models.ManyToManyField(
        'people.Student', 
        through='ChatParticipantStudent',
        related_name='chat_rooms', 
        blank=True
    )
    
    # Group settings
    is_encrypted = models.BooleanField(default=True, help_text="Enable end-to-end encryption")
    encryption_key = models.TextField(null=True, blank=True, help_text="Encrypted room key")
    
    # Admin/Moderators
    admins = models.JSONField(default=list, help_text="List of admin user IDs with types")
    moderators = models.JSONField(default=list, help_text="List of moderator user IDs with types")
    
    # Metadata
    created_by_type = models.CharField(max_length=20, null=True, blank=True)
    created_by_id = models.CharField(max_length=100, null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    is_active = models.BooleanField(default=True)
    last_message_at = models.DateTimeField(null=True, blank=True)
    
    # Group settings
    allow_media = models.BooleanField(default=True)
    allow_links = models.BooleanField(default=True)
    slow_mode = models.IntegerField(default=0, help_text="Seconds between messages")
    join_by_invite_only = models.BooleanField(default=False)
    
    class Meta:
        db_table = 'chat_rooms'
        ordering = ['-last_message_at']
        indexes = [
            models.Index(fields=['room_type']),
            models.Index(fields=['academic_class']),
            models.Index(fields=['subject']),
            models.Index(fields=['is_active']),
            models.Index(fields=['last_message_at']),
        ]
        
    
    def __str__(self):
        if self.name:
            return self.name
        if self.academic_class:
            return f"{self.academic_class} - {self.room_type}"
        return f"Chat {self.id}"
    
    def get_participants(self):
        """Get all participants in the room"""
        participants = []
        
        # Get teachers
        for participant in self.chatparticipantteacher_set.filter(is_active=True):
            participants.append(participant.get_user_data())
        
        # Get parents
        for participant in self.chatparticipantparent_set.filter(is_active=True):
            participants.append(participant.get_user_data())
        
        # Get students
        for participant in self.chatparticipantstudent_set.filter(is_active=True):
            participants.append(participant.get_user_data())
        
        return participants


class BaseChatParticipant(models.Model):
    """Abstract base class for chat participants"""
    
    ROLE_CHOICES = [
        ('MEMBER', 'Member'),
        ('MODERATOR', 'Moderator'),
        ('ADMIN', 'Admin'),
    ]
    
    room = models.ForeignKey(ChatRoom, on_delete=models.CASCADE, related_name='%(class)s_set')
    
    # Role and permissions
    role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='MEMBER')
    
    # Settings
    is_muted = models.BooleanField(default=False)
    muted_until = models.DateTimeField(null=True, blank=True)
    notification_enabled = models.BooleanField(default=True)
    last_read_at = models.DateTimeField(null=True, blank=True)
    pinned = models.BooleanField(default=False)
    
    # Encryption
    public_key = models.TextField(null=True, blank=True)
    private_key_encrypted = models.TextField(null=True, blank=True)
    
    # Timestamps
    joined_at = models.DateTimeField(auto_now_add=True)
    left_at = models.DateTimeField(null=True, blank=True)
    last_active_at = models.DateTimeField(auto_now=True)
    is_active = models.BooleanField(default=True)
    
    class Meta:
        abstract = True
    
    def has_permission(self, action):
        """Check if user has permission for specific actions"""
        if self.role == 'ADMIN':
            return True
        elif self.role == 'MODERATOR':
            return action in ['delete_message', 'mute_user', 'pin_message']
        else:  # MEMBER
            return action in ['send_message', 'read_message', 'edit_own_message']
    
    def update_last_active(self):
        """Update last active timestamp"""
        self.last_active_at = timezone.now()
        self.save(update_fields=['last_active_at'])


class ChatParticipantTeacher(BaseChatParticipant):
    """Teacher participant in chat room"""
    
    teacher = models.ForeignKey('people.Teacher', on_delete=models.CASCADE, related_name='chat_participations')
    
    class Meta:
        db_table = 'chat_participant_teachers'
        unique_together = ['room', 'teacher']
        indexes = [
            models.Index(fields=['teacher', 'is_active']),
            models.Index(fields=['is_muted']),
            models.Index(fields=['role']),
        ]
    
    def __str__(self):
        return f"{self.teacher} in {self.room}"
    
    def get_user_data(self):
        """Get teacher user data"""
        return {
            'type': 'teacher',
            'id': str(self.teacher.id),
            'name': self.teacher.full_name,
            'email': self.teacher.email,
            'profile_image': self.teacher.profile_image.url if self.teacher.profile_image else None,
            'role': self.role
        }


class ChatParticipantParent(BaseChatParticipant):
    """Parent participant in chat room"""
    
    parent = models.ForeignKey('people.Parent', on_delete=models.CASCADE, related_name='chat_participations')
    
    class Meta:
        db_table = 'chat_participant_parents'
        unique_together = ['room', 'parent']
        indexes = [
            models.Index(fields=['parent', 'is_active']),
            models.Index(fields=['is_muted']),
            models.Index(fields=['role']),
        ]
    
    def __str__(self):
        return f"{self.parent} in {self.room}"
    
    def get_user_data(self):
        """Get parent user data"""
        return {
            'type': 'parent',
            'id': str(self.parent.id),
            'name': self.parent.full_name,
            'email': self.parent.email,
            'profile_image': self.parent.profile_image.url if self.parent.profile_image else None,
            'role': self.role
        }


class ChatParticipantStudent(BaseChatParticipant):
    """Student participant in chat room"""
    
    student = models.ForeignKey('people.Student', on_delete=models.CASCADE, related_name='chat_participations')
    
    class Meta:
        db_table = 'chat_participant_students'
        unique_together = ['room', 'student']
        indexes = [
            models.Index(fields=['student', 'is_active']),
            models.Index(fields=['is_muted']),
            models.Index(fields=['role']),
        ]
    
    def __str__(self):
        return f"{self.student} in {self.room}"
    
    def get_user_data(self):
        """Get student user data"""
        return {
            'type': 'student',
            'id': str(self.student.id),
            'name': self.student.full_name,
            'email': self.student.personal_email,
            'profile_image': self.student.profile_image.url if self.student.profile_image else None,
            'role': self.role,
            'roll_number': self.student.roll_number,
            'student_id': self.student.student_id
        }


class Message(models.Model):
    """Enhanced message with encryption support"""
    
    MESSAGE_TYPES = [
        ('TEXT', 'Text'),
        ('IMAGE', 'Image'),
        ('FILE', 'File'),
        ('AUDIO', 'Audio'),
        ('VIDEO', 'Video'),
        ('SYSTEM', 'System'),
        ('POLL', 'Poll'),
        ('ANNOUNCEMENT', 'Announcement'),
        ('ASSIGNMENT', 'Assignment'),
    ]
    
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    room = models.ForeignKey(ChatRoom, on_delete=models.CASCADE, related_name='messages')
    
    # Sender information
    sender_type = models.CharField(max_length=20)  # 'teacher', 'parent', 'student'
    sender_id = models.CharField(max_length=100)
    
    # Message content (encrypted)
    message_type = models.CharField(max_length=20, choices=MESSAGE_TYPES, default='TEXT')
    content_encrypted = models.TextField(null=True, blank=True)
    content = models.TextField(null=True, blank=True)
    
    # File attachments
    file = models.FileField(upload_to='chat_files/%Y/%m/%d/', null=True, blank=True)
    file_name = models.CharField(max_length=255, null=True, blank=True)
    file_size = models.IntegerField(null=True, blank=True)
    file_type = models.CharField(max_length=100, null=True, blank=True)
    thumbnail = models.ImageField(upload_to='chat_thumbnails/%Y/%m/%d/', null=True, blank=True)
    
    # Reply to message
    reply_to = models.ForeignKey(
        'self',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='replies'
    )
    
    # Message status
    is_encrypted = models.BooleanField(default=False)
    is_read = models.BooleanField(default=False)
    read_at = models.DateTimeField(null=True, blank=True)
    is_deleted = models.BooleanField(default=False)
    deleted_at = models.DateTimeField(null=True, blank=True)
    deleted_by_type = models.CharField(max_length=20, null=True, blank=True)
    deleted_by_id = models.CharField(max_length=100, null=True, blank=True)
    
    # Edit history
    edited_at = models.DateTimeField(null=True, blank=True)
    edit_history = models.JSONField(default=list)
    
    # Reactions
    reactions = models.JSONField(default=dict)
    
    # Metadata
    metadata = models.JSONField(default=dict)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        db_table = 'messages'
        ordering = ['created_at']
        indexes = [
            models.Index(fields=['room', 'created_at']),
            models.Index(fields=['sender_type', 'sender_id']),
            models.Index(fields=['is_read']),
            models.Index(fields=['message_type']),
        ]
    
    def __str__(self):
        return f"{self.sender_type}: {self.content[:50] if self.content else '[Encrypted]'}"
    
    def get_sender_name(self):
        """Get sender's display name"""
        if self.sender_type == 'teacher':
            from people.models import Teacher
            try:
                teacher = Teacher.objects.get(id=self.sender_id)
                return teacher.full_name
            except Teacher.DoesNotExist:
                return 'Unknown Teacher'
        elif self.sender_type == 'parent':
            from people.models import Parent
            try:
                parent = Parent.objects.get(id=self.sender_id)
                return parent.full_name
            except Parent.DoesNotExist:
                return 'Unknown Parent'
        elif self.sender_type == 'student':
            from people.models import Student
            try:
                student = Student.objects.get(id=self.sender_id)
                return student.full_name
            except Student.DoesNotExist:
                return 'Unknown Student'
        return 'Unknown User'
    
    def get_sender_details(self):
        """Get complete sender details"""
        if self.sender_type == 'teacher':
            from people.models import Teacher
            try:
                teacher = Teacher.objects.get(id=self.sender_id)
                return {
                    'id': str(teacher.id),
                    'name': teacher.full_name,
                    'email': teacher.email,
                    'type': 'teacher',
                    'profile_image': teacher.profile_image.url if teacher.profile_image else None
                }
            except Teacher.DoesNotExist:
                return None
        elif self.sender_type == 'parent':
            from people.models import Parent
            try:
                parent = Parent.objects.get(id=self.sender_id)
                return {
                    'id': str(parent.id),
                    'name': parent.full_name,
                    'email': parent.email,
                    'type': 'parent',
                    'profile_image': parent.profile_image.url if parent.profile_image else None
                }
            except Parent.DoesNotExist:
                return None
        elif self.sender_type == 'student':
            from people.models import Student
            try:
                student = Student.objects.get(id=self.sender_id)
                return {
                    'id': str(student.id),
                    'name': student.full_name,
                    'email': student.personal_email,
                    'type': 'student',
                    'profile_image': student.profile_image.url if student.profile_image else None,
                    'roll_number': student.roll_number
                }
            except Student.DoesNotExist:
                return None
        return None
    
    def mark_as_read(self):
        """Mark message as read"""
        if not self.is_read:
            self.is_read = True
            self.read_at = timezone.now()
            self.save(update_fields=['is_read', 'read_at'])


class MessageReadReceipt(models.Model):
    """Track who has read which messages"""
    
    message = models.ForeignKey(Message, on_delete=models.CASCADE, related_name='read_receipts')
    user_type = models.CharField(max_length=20)
    user_id = models.CharField(max_length=100)
    read_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        db_table = 'message_read_receipts'
        unique_together = ['message', 'user_type', 'user_id']
        indexes = [
            models.Index(fields=['user_type', 'user_id']),
        ]
    
    def __str__(self):
        return f"{self.user_type} {self.user_id} read {self.message.id}"


class MessageDelivery(models.Model):
    """Track message delivery status"""
    
    DELIVERY_STATUS = [
        ('SENT', 'Sent'),
        ('DELIVERED', 'Delivered'),
        ('READ', 'Read'),
        ('FAILED', 'Failed'),
    ]
    
    message = models.ForeignKey(Message, on_delete=models.CASCADE, related_name='delivery_status')
    user_type = models.CharField(max_length=20)
    user_id = models.CharField(max_length=100)
    status = models.CharField(max_length=20, choices=DELIVERY_STATUS, default='SENT')
    delivered_at = models.DateTimeField(null=True, blank=True)
    read_at = models.DateTimeField(null=True, blank=True)
    failed_reason = models.TextField(null=True, blank=True)
    
    class Meta:
        db_table = 'message_delivery'
        unique_together = ['message', 'user_type', 'user_id']
        indexes = [
            models.Index(fields=['user_type', 'user_id', 'status']),
        ]


class ChatInvitation(models.Model):
    """Invitations for private groups"""
    
    INVITATION_STATUS = [
        ('PENDING', 'Pending'),
        ('ACCEPTED', 'Accepted'),
        ('REJECTED', 'Rejected'),
        ('EXPIRED', 'Expired'),
    ]
    
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    room = models.ForeignKey(ChatRoom, on_delete=models.CASCADE, related_name='invitations')
    
    # Invitee
    user_type = models.CharField(max_length=20)
    user_id = models.CharField(max_length=100)
    
    # Inviter
    invited_by_type = models.CharField(max_length=20)
    invited_by_id = models.CharField(max_length=100)
    
    status = models.CharField(max_length=20, choices=INVITATION_STATUS, default='PENDING')
    expires_at = models.DateTimeField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        db_table = 'chat_invitations'
        unique_together = ['room', 'user_type', 'user_id']
        indexes = [
            models.Index(fields=['user_type', 'user_id', 'status']),
            models.Index(fields=['expires_at']),
        ]


class ChatMention(models.Model):
    """Track mentions in messages"""
    
    message = models.ForeignKey(Message, on_delete=models.CASCADE, related_name='mentions')
    user_type = models.CharField(max_length=20)
    user_id = models.CharField(max_length=100)
    is_notified = models.BooleanField(default=False)
    notified_at = models.DateTimeField(null=True, blank=True)
    
    class Meta:
        db_table = 'chat_mentions'
        indexes = [
            models.Index(fields=['user_type', 'user_id']),
            models.Index(fields=['is_notified']),
        ]


class ChatPoll(models.Model):
    """Polls in chat rooms"""
    
    message = models.OneToOneField(Message, on_delete=models.CASCADE, related_name='poll')
    question = models.CharField(max_length=500)
    options = models.JSONField()
    is_multiple = models.BooleanField(default=False)
    is_anonymous = models.BooleanField(default=False)
    ends_at = models.DateTimeField()
    created_by_type = models.CharField(max_length=20)
    created_by_id = models.CharField(max_length=100)
    total_votes = models.IntegerField(default=0)
    
    class Meta:
        db_table = 'chat_polls'
    
    def get_results(self):
        """Get poll results"""
        from django.db.models import Count
        votes = self.votes.values('option_index').annotate(count=Count('id'))
        results = {v['option_index']: v['count'] for v in votes}
        return results


class ChatPollVote(models.Model):
    """Votes on polls"""
    
    poll = models.ForeignKey(ChatPoll, on_delete=models.CASCADE, related_name='votes')
    user_type = models.CharField(max_length=20)
    user_id = models.CharField(max_length=100)
    option_index = models.IntegerField()
    voted_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        db_table = 'chat_poll_votes'
        unique_together = ['poll', 'user_type', 'user_id']