from datetime import timedelta
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.conf import settings
import urllib.parse

# Event Model
class Event(models.Model):
    STATUS_CHOICES = [
        ('upcoming', 'Upcoming'),
        ('ongoing', 'Ongoing'),
        ('archived', 'Archived'),
    ]

    DEFAULT_EVENT_DURATION = timedelta(hours=24)  # Configurable duration

    title = models.CharField(max_length=200)
    description = models.TextField()
    date_time = models.DateTimeField()
    end_time = models.DateTimeField(null=True, blank=True)
    venue = models.CharField(max_length=200)
    status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='upcoming')
    banner_image = models.ImageField(upload_to='event_banners/', blank=True, null=True)
    registration_open = models.BooleanField(default=False, help_text='Enable this to allow users to register for this event')
    
    # Live streaming fields
    stream_url = models.URLField(
        blank=True, 
        null=True,
        help_text='Facebook live stream URL. Will be shown when event is ongoing.'
    )
    stream_platform = models.CharField(
        max_length=10,
        choices=[('facebook', 'Facebook')],  # Only Facebook is available
        blank=True,
        null=True,
        help_text='Platform where the event will be streamed'
    )

    def __str__(self):
        return self.title

    def save(self, *args, **kwargs):
        now = timezone.now()

        # Update status based on current time
        if self.is_upcoming:
            self.status = 'upcoming'
        elif self.is_ongoing:
            self.status = 'ongoing'
        else:
            self.status = 'archived'
        
        super().save(*args, **kwargs)

    def can_register(self):
        """Check if registration is allowed for this event"""
        return self.is_upcoming and self.registration_open

    @property
    def is_upcoming(self):
        """Check if the event is upcoming"""
        return self.date_time > timezone.now()

    @property
    def is_ongoing(self):
        """Check if the event is currently ongoing"""
        now = timezone.now()
        if self.end_time:
            return self.date_time <= now <= self.end_time
        else:
            event_end_time = self.date_time + self.DEFAULT_EVENT_DURATION
            return self.date_time <= now <= event_end_time

    @property
    def is_archived(self):
        """Check if the event has ended"""
        now = timezone.now()
        if self.end_time:
            return now > self.end_time
        else:
            event_end_time = self.date_time + self.DEFAULT_EVENT_DURATION
            return now > event_end_time

    @property
    def has_stream(self):
        """Check if event has a valid stream URL"""
        # return bool(self.stream_url and self.stream_platform)
        return bool(self.stream_url)  # Only check URL exists, don't check platform


    @property
    def embedded_stream_url(self):
        """Convert regular URL to embedded URL format"""
        if not self.has_stream:
            return None
            
        if '/videos/' in self.stream_url:
            return f'https://www.facebook.com/plugins/video.php?href={urllib.parse.quote(self.stream_url)}&show_text=false&width=500&height=282'
        
        # For all other URLs, use the post plugin
        encoded_url = urllib.parse.quote(self.stream_url)
        return f'https://www.facebook.com/plugins/post.php?href={encoded_url}&show_text=true&width=500'
        # return None

    @property
    def direct_url(self):
        """Get the direct URL for the video platform"""
        if not self.has_stream:
            return None
        return self.stream_url

    @property
    def stream_available(self):
        """Check if stream should be shown (has URL and is ongoing)"""
        return self.has_stream

from django.core.exceptions import ValidationError
from django.core.files.images import get_image_dimensions

def validate_speaker_photo(image):
    if image:
        w, h = get_image_dimensions(image)
        min_dimension = 400  # Minimum width/height
        max_dimension = 4000  # Maximum width/height
        max_size = 5 * 1024 * 1024  # 5MB

        if w < min_dimension or h < min_dimension:
            raise ValidationError(
                f'Image dimensions must be at least {min_dimension}x{min_dimension} pixels. '
                f'Your image is {w}x{h} pixels.'
            )
        if w > max_dimension or h > max_dimension:
            raise ValidationError(
                f'Image dimensions cannot exceed {max_dimension}x{max_dimension} pixels. '
                f'Your image is {w}x{h} pixels.'
            )
        if image.size > max_size:
            raise ValidationError(
                f'Image file size cannot exceed 2MB. Your file is {image.size/1024/1024:.1f}MB.'
            )
        if w != h:
            raise ValidationError(
                'Image must be square (same width and height). '
                f'Your image is {w}x{h} pixels.'
            )

def validate_social_media(value):
    if not value:
        return

    required_keys = ['twitter', 'linkedin', 'github', 'website']
    for key in value.keys():
        if key not in required_keys:
            raise ValidationError(f'Invalid social media key: {key}')
        
        if key == 'twitter' and value[key] and not value[key].startswith('@'):
            raise ValidationError('Twitter handle must start with @')
        
        if key in ['linkedin', 'github', 'website'] and value[key]:
            if not value[key].startswith(('http://', 'https://')):
                raise ValidationError(f'{key.title()} must be a full URL starting with http:// or https://')

# Speaker Model
class Speaker(models.Model):
    name = models.CharField(max_length=100)
    title = models.CharField(
        max_length=100, 
        blank=True, 
        help_text='Job title or role, e.g. "Full Stack Developer"'
    )
    bio = models.TextField(
        help_text='A brief description of the speaker\'s background and expertise'
    )
    photo = models.ImageField(
        upload_to='speaker_photos/', 
        blank=True,
        validators=[validate_speaker_photo],
        help_text='Square image, minimum 400x400px, maximum 1200x1200px, max 2MB'
    )
    organization = models.CharField(
        max_length=200, 
        blank=True,
        help_text='Organization or company the speaker represents'
    )
    website = models.URLField(
        blank=True,
        help_text='Personal or professional website URL'
    )
    social_media = models.JSONField(
        default=dict, 
        blank=True,
        validators=[validate_social_media],
        help_text='Social media links in JSON format. Example: {"twitter": "@username", "linkedin": "https://linkedin.com/in/username", "github": "https://github.com/username", "website": "https://example.com"}'
    )
    events = models.ManyToManyField(
        Event, 
        related_name='speakers',
        blank=True,
        help_text='Events this speaker is participating in'
    )
    created_at = models.DateTimeField(auto_now_add=True)

    def get_twitter_url(self):
        """Get the full Twitter URL from the handle"""
        if self.social_media and self.social_media.get('twitter'):
            handle = self.social_media['twitter'].lstrip('@')
            return f'https://twitter.com/{handle}'
        return None

    def get_social_links(self):
        """Get all social media links in a structured format"""
        links = []
        if self.social_media:
            if twitter := self.get_twitter_url():
                links.append({
                    'url': twitter,
                    'icon': 'bi-twitter',
                    'name': 'Twitter'
                })
            if linkedin := self.social_media.get('linkedin'):
                links.append({
                    'url': linkedin,
                    'icon': 'bi-linkedin',
                    'name': 'LinkedIn'
                })
            if github := self.social_media.get('github'):
                links.append({
                    'url': github,
                    'icon': 'bi-github',
                    'name': 'GitHub'
                })
            if website := (self.website or self.social_media.get('website')):
                links.append({
                    'url': website,
                    'icon': 'bi-globe',
                    'name': 'Website'
                })
        return links

    def __str__(self):
        return self.name

# Agenda Model
class Agenda(models.Model):
    event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='agendas')
    session_title = models.CharField(max_length=200)
    session_time = models.DateTimeField()
    description = models.TextField()
    speakers = models.ManyToManyField(
        Speaker, 
        related_name='agendas',
        blank=True,
        help_text='Speakers for this session. Leave empty if no specific speakers.'
    )

    def __str__(self):
        return self.session_title

    class Meta:
        ordering = ['session_time']
        verbose_name = 'Agenda Item'
        verbose_name_plural = 'Agenda Items'

# Call for Proposals Model
class CallForProposal(models.Model):
    event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='cfps')
    title = models.CharField(max_length=200)
    image = models.ImageField(upload_to='cfp_images/', blank=True, null=True, help_text='Image to display on the CFP card')
    description = models.TextField()
    submission_deadline = models.DateTimeField()
    STATUS_CHOICES = [
        ('open', 'Open'),
        ('closed', 'Closed'),
        ('under_review', 'Under Review')
    ]
    status = models.CharField(max_length=15, choices=STATUS_CHOICES, default='open')
    created_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='created_cfps'
    )
    created_at = models.DateTimeField(default=timezone.now)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.title

    def save(self, *args, **kwargs):
        # Update status based on deadline
        now = timezone.now()
        if self.status != 'under_review':  # Don't auto-change if under review
            if now > self.submission_deadline or not self.event.is_upcoming:
                self.status = 'closed'
            else:
                self.status = 'open'
        super().save(*args, **kwargs)

    @property
    def is_open(self):
        """Check if CFP is open for submissions"""
        now = timezone.now()
        return (
            self.status == 'open' and 
            now <= self.submission_deadline and
            self.event.is_upcoming
        )

    @property
    def is_closed(self):
        """Check if CFP is closed"""
        return self.status == 'closed' or timezone.now() > self.submission_deadline

    @property
    def is_under_review(self):
        """Check if CFP is under review"""
        return self.status == 'under_review'

    @property
    def status_badge_class(self):
        """Return Bootstrap badge class based on status"""
        if self.is_under_review:
            return 'bg-info'
        elif self.is_open:
            return 'bg-success'
        else:
            return 'bg-danger'

    @property
    def time_remaining(self):
        """Return submission deadline for timeuntil filter"""
        if self.is_open:
            return self.submission_deadline
        return None

class SessionType(models.Model):
    """Model for session types that can be configured from admin"""
    name = models.CharField(max_length=100, unique=True)
    description = models.TextField(blank=True)
    
    def __str__(self):
        return self.name
    
    class Meta:
        ordering = ['name']


class Proposal(models.Model):
    cfp = models.ForeignKey(CallForProposal, on_delete=models.CASCADE, related_name='proposals')
    # New fields
    organisation = models.CharField(max_length=200, help_text="Your organization name")
    contact_number = models.CharField(max_length=20, help_text="Your contact phone number")
    title = models.CharField(max_length=200)
    sub_theme = models.CharField(max_length=200, blank=True, help_text="Optional sub-theme for your proposal")
    abstract = models.TextField(help_text="Provide a clear and concise description of your presentation")
    # Changed from presentation_type to session_type with ForeignKey
    session_type = models.ForeignKey(SessionType, on_delete=models.CASCADE, related_name='proposals')
    learning_objectives = models.TextField(help_text="What participants will learn from your session")
    SPONSORSHIP_CHOICES = [
        ('yes', 'Yes, I will sponsor my session'),
        ('no', 'No, I need sponsorship')
    ]
    sponsorship = models.CharField(
        max_length=3, 
        choices=SPONSORSHIP_CHOICES,
        help_text="Are you sponsoring your session or do you need sponsorship? Note: Priority is given to session proposers who will contribute to the event costs"
    )
    # Document upload fields - removed presentation_slides
    supporting_document = models.FileField(
        upload_to='proposal_documents/', 
        blank=True, 
        null=True,
        help_text='Additional supporting documents (PDF format)'
    )
    additional_notes = models.TextField(blank=True, help_text="Any additional information you'd like to share with the reviewers")
    submitter = models.ForeignKey(User, on_delete=models.CASCADE, related_name='submitted_proposals')
    STATUS_CHOICES = [
        ('submitted', 'Submitted'),
        ('under_review', 'Under Review'),
        ('accepted', 'Accepted'),
        ('rejected', 'Rejected')
    ]
    status = models.CharField(max_length=15, choices=STATUS_CHOICES, default='submitted')
    submitted_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    reviewer_notes = models.TextField(blank=True)
    reviewed_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='reviewed_proposals'
    )
    reviewed_at = models.DateTimeField(null=True, blank=True)

    def __str__(self):
        return self.title

    def review(self, reviewer, status, notes=''):
        self.status = status
        self.reviewer_notes = notes
        self.reviewed_by = reviewer
        self.reviewed_at = timezone.now()
        self.save()

    class Meta:
        unique_together = ['title', 'submitter', 'cfp']
        ordering = ['-submitted_at']
        verbose_name = 'Proposal'
        verbose_name_plural = 'Proposals'


class PublicationType(models.Model):
    """Model for managing publication types"""
    name = models.CharField(max_length=50, unique=True)
    icon = models.CharField(
        max_length=50,
        default='bi-file-earmark',
        help_text='Bootstrap icon class (e.g., bi-file-earmark-pdf)'
    )
    allowed_extensions = models.CharField(
        max_length=200,
        help_text='Comma-separated list of allowed file extensions (e.g., .pdf,.doc,.ppt)',
        default='.pdf,.doc,.docx,.ppt,.pptx'
    )
    
    def __str__(self):
        return self.name
    
    class Meta:
        verbose_name = 'Publication Type'
        verbose_name_plural = 'Publication Types'
        ordering = ['name']

class Publication(models.Model):
    """Model for standalone publications not tied to proposals"""
    title = models.CharField(max_length=255)
    abstract = models.TextField(
        help_text='Brief description of the publication'
    )
    author = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        help_text='Who authored/uploaded this publication'
    )
    publication_type = models.ForeignKey(
        PublicationType,
        on_delete=models.PROTECT,
        help_text='Type of publication'
    )
    file = models.FileField(
        upload_to='publications/',
        help_text='Upload your publication file'
    )
    # event = models.ForeignKey(
    #     'Event',
    #     on_delete=models.SET_NULL,  # Changed from CASCADE to SET_NULL
    #     null=True,
    #     blank=True,
    #     help_text='Optional: Associate this publication with an event'
    # )
    published_at = models.DateTimeField(
        auto_now_add=True,
        help_text='When this publication was made available'
    )
    is_public = models.BooleanField(
        default=True,
        help_text='Make this publication visible to all users'
    )

    def __str__(self):
        return self.title

    def can_be_published(self):
        """Check if the publication meets requirements for being public"""
        # Must have a file
        if not self.file or not self.file.name:
            return False
            
        try:
            # File must exist on disk
            if not self.file.storage.exists(self.file.name):
                return False
                
            # If associated with an event, event must be archived (more than 2 hours old)
            if self.event:
                now = timezone.now()
                two_hours_ago = now - timezone.timedelta(hours=2)
                if self.event.date_time > two_hours_ago:
                    return False
                
            return True
        except Exception:
            return False
            
    def get_publication_type_display(self):
        """Return the display name for the publication type"""
        return dict(self.PUBLICATION_TYPES).get(self.publication_type, 'Unknown')

    class Meta:
        ordering = ['-published_at']
        verbose_name = 'Publication'
        verbose_name_plural = 'Publications'

# Gallery Model
class Gallery(models.Model):
    event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='gallery')
    image = models.ImageField(upload_to='gallery_images/')
    caption = models.CharField(max_length=200)
    # Add a field to store the original filename for duplicate detection
    original_filename = models.CharField(max_length=255, blank=True, null=True)
    
    def save(self, *args, **kwargs):
        # Set the original filename if not already set
        if self.image and not self.original_filename:
            self.original_filename = self.image.name.split('/')[-1]
        super().save(*args, **kwargs)

    def __str__(self):
        return f"{self.event.title} - {self.caption}"

    class Meta:
        verbose_name = 'Gallery Image'
        verbose_name_plural = 'Gallery Images'
        ordering = ['-id']
        # Use original_filename instead of image for uniqueness constraint
        unique_together = ['event', 'original_filename']

# Carousel Image Model
class CarouselImage(models.Model):
    title = models.CharField(max_length=100, help_text="A descriptive title for the image")
    image = models.ImageField(
        upload_to='carousel/',
        help_text="Recommended size: 1920x1080px. Images will be cropped/scaled to fit."
    )
    caption = models.CharField(
        max_length=200, 
        blank=True,
        help_text="Optional caption to display over the image"
    )
    is_active = models.BooleanField(
        default=True,
        help_text="Only active images will be shown in the carousel"
    )
    order = models.PositiveIntegerField(
        default=0,
        help_text="Images will be displayed in ascending order"
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['order', '-created_at']
        verbose_name = 'Carousel Image'
        verbose_name_plural = 'Carousel Images'

    def __str__(self):
        return self.title

# Section Image Model
class SectionImage(models.Model):
    SECTION_CHOICES = [
        ('join_community', 'Join Community Section'),
        # ('about', 'About Section'),
        # ('hero', 'Hero Section'),
        # ('event', 'Event Section'),
    ]
    
    section = models.CharField(
        max_length=50, 
        choices=SECTION_CHOICES,
        unique=True,
        help_text="The section where this image will be displayed"
    )
    title = models.CharField(max_length=100, help_text="A descriptive title for the image")
    image = models.ImageField(
        upload_to='section_images/',
        help_text="Image for the section (recommended size: 800x600px)"
    )
    caption = models.CharField(
        max_length=200, 
        blank=True,
        help_text="Optional caption for the image"
    )
    is_active = models.BooleanField(
        default=True,
        help_text="Only active images will be shown"
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name = 'Section Image'
        verbose_name_plural = 'Section Images'

    def __str__(self):
        return f"{self.get_section_display()} - {self.title}"

# Sponsor Model
class Sponsor(models.Model):
    name = models.CharField(max_length=100, help_text='Name of the sponsor')
    logo = models.ImageField(
        upload_to='sponsors/',
        help_text='Sponsor logo (recommended size: 300x200px)'
    )
    website = models.URLField(
        blank=True, 
        null=True,
        help_text='URL to sponsor\'s website'
    )
    is_active = models.BooleanField(
        default=True,
        help_text='Whether to show this sponsor in the carousel'
    )
    order = models.PositiveIntegerField(
        default=0,
        help_text='Order in which to display the sponsor (lower numbers first)'
    )
    events = models.ManyToManyField(
        'Event',
        related_name='sponsors',
        blank=True,
        help_text='Events this sponsor is associated with'
    )

    class Meta:
        ordering = ['order', 'name']

    def __str__(self):
        return self.name

# User Roles
class Role(models.Model):
    ROLE_CHOICES = [
        ('admin', 'Admin'),
        ('editor', 'Editor'),
        ('attendee', 'Attendee'),
    ]
    name = models.CharField(max_length=50, choices=ROLE_CHOICES, unique=True)
    permissions = models.JSONField(default=dict, blank=True, help_text='Store role-specific permissions')

    def __str__(self):
        return self.get_name_display()
    
    def save(self, *args, **kwargs):
        # Define default permissions for each role
        if not self.permissions:
            if self.name == 'admin':
                self.permissions = {
                    'can_manage_events': True,
                    'can_manage_users': True,
                    'can_manage_roles': True,
                    'can_manage_gallery': True,
                    'can_approve_proposals': True,
                    'can_view_reports': True,
                }
            elif self.name == 'editor':
                self.permissions = {
                    'can_manage_events': True,
                    'can_manage_gallery': True,
                    'can_approve_proposals': True,
                    'can_view_reports': False,
                }
            else:  # attendee
                self.permissions = {
                    'can_register_events': True,
                    'can_submit_proposals': True,
                    'can_view_events': True,
                }
        super().save(*args, **kwargs)
    
    class Meta:
        verbose_name = 'Role'
        verbose_name_plural = 'Roles'
        ordering = ['name']

# UserProfile Model (extends Django's User model)
class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    role = models.ForeignKey(Role, on_delete=models.CASCADE)
    bio = models.TextField(blank=True)
    organization = models.CharField(max_length=200, blank=True)
    phone_number = models.CharField(max_length=20, blank=True)
    profile_picture = models.ImageField(upload_to='profile_pictures/', blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return f"{self.user.username}'s Profile"
    
    def get_role_display(self):
        """Get the user's role display name based on permissions."""
        if self.user.is_superuser:
            return 'Superuser'
        elif self.user.is_staff:
            return 'Staff'
        else:
            return 'Attendee'
    
    def get_role_color(self):
        """Get the appropriate Bootstrap color class for the user's role."""
        if self.user.is_superuser:
            return 'primary'
        elif self.user.is_staff:
            return 'info'
        else:
            return 'secondary'

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    """Create a UserProfile for new users with default attendee role"""
    if created:
        # Get or create the attendee role
        attendee_role, _ = Role.objects.get_or_create(
            name='attendee',
            defaults={
                'permissions': {
                    'can_register_events': True,
                    'can_submit_proposals': True,
                    'can_view_events': True
                }
            }
        )
        
        # Get or create the user profile
        UserProfile.objects.get_or_create(
            user=instance,
            defaults={'role': attendee_role}
        )

# Registration Model
class Registration(models.Model):
    event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='registrations')
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    STATUS_CHOICES = [
        ('registered', 'Registered'),
        ('attended', 'Attended'),
        ('cancelled', 'Cancelled')
    ]
    status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='registered')
    registration_date = models.DateTimeField(auto_now_add=True)
    attendance_date = models.DateTimeField(null=True, blank=True)
    notes = models.TextField(blank=True)

    class Meta:
        unique_together = ['event', 'user']

    def __str__(self):
        return f"{self.user.username} - {self.event.title}"

    def mark_as_attended(self):
        self.status = 'attended'
        self.attendance_date = timezone.now()
        self.save()
