import string
import uuid

from django.conf import settings
from django.db import models
from django.utils.crypto import get_random_string


def generate_short_id():
    return get_random_string(6, allowed_chars=string.ascii_uppercase + string.digits)


# ---------------------------------------------------------------------------
# ClassType
# ---------------------------------------------------------------------------
class ClassType(models.Model):
    class DifficultyLevel(models.TextChoices):
        BEGINNER = "beginner", "Beginner"
        INTERMEDIATE = "intermediate", "Intermediate"
        ADVANCED = "advanced", "Advanced"
        ALL_LEVELS = "all_levels", "All Levels"

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    gym = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='gym_class_types',
    )
    name = models.CharField(max_length=150)
    description = models.TextField(blank=True, default="")
    category = models.CharField(max_length=100, blank=True, default="")
    default_duration_minutes = models.PositiveIntegerField(default=60)
    default_capacity = models.PositiveIntegerField(default=20)
    max_participants = models.PositiveIntegerField(default=30)
    required_equipment = models.TextField(blank=True, default="")
    color_hex = models.CharField(max_length=7, default="#3B82F6")
    difficulty_level = models.CharField(
        max_length=20,
        choices=DifficultyLevel.choices,
        default=DifficultyLevel.ALL_LEVELS,
    )
    image = models.ImageField(upload_to="scheduling/class_types/", blank=True, null=True)
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["name"]

    def __str__(self):
        return self.name


# ---------------------------------------------------------------------------
# Room
# ---------------------------------------------------------------------------
class Room(models.Model):
    class RoomType(models.TextChoices):
        STUDIO = "studio", "Studio"
        HALL = "hall", "Hall"
        OUTDOOR = "outdoor", "Outdoor"
        VIRTUAL = "virtual", "Virtual"

    class RoomStatus(models.TextChoices):
        AVAILABLE = "available", "Available"
        UNDER_MAINTENANCE = "under_maintenance", "Under Maintenance"

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    gym = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='gym_rooms',
    )
    name = models.CharField(max_length=150)
    location = models.ForeignKey(
        "core.Location",
        on_delete=models.SET_NULL,
        related_name="rooms",
        blank=True,
        null=True,
    )
    capacity = models.PositiveIntegerField(default=0)
    description = models.TextField(blank=True, default="")
    amenities = models.JSONField(default=list, blank=True)
    room_type = models.CharField(
        max_length=20,
        choices=RoomType.choices,
        default=RoomType.STUDIO,
    )
    status = models.CharField(
        max_length=20,
        choices=RoomStatus.choices,
        default=RoomStatus.AVAILABLE,
    )
    equipment_available = models.TextField(blank=True, default="")
    notes = models.TextField(blank=True, default="")
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["name"]

    def __str__(self):
        return self.name


# ---------------------------------------------------------------------------
# ClassSession
# ---------------------------------------------------------------------------
class ClassSession(models.Model):
    class Status(models.TextChoices):
        ACTIVE = "active", "Active"
        SCHEDULED = "scheduled", "Scheduled"
        IN_PROGRESS = "in_progress", "In Progress"
        COMPLETED = "completed", "Completed"
        CANCELLED = "cancelled", "Cancelled"

    class RecurrenceType(models.TextChoices):
        ONE_TIME = "one_time", "One Time"
        DAILY = "daily", "Daily"
        WEEKLY = "weekly", "Weekly"

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    short_id = models.CharField(max_length=6, unique=True, default=generate_short_id)
    class_type = models.ForeignKey(
        ClassType,
        on_delete=models.CASCADE,
        related_name="sessions",
    )
    instructor = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="instructed_sessions",
    )
    room = models.ForeignKey(
        Room,
        on_delete=models.SET_NULL,
        related_name="sessions",
        blank=True,
        null=True,
    )
    location = models.ForeignKey(
        "core.Location",
        on_delete=models.SET_NULL,
        related_name="class_sessions",
        blank=True,
        null=True,
    )
    title = models.CharField(max_length=200)
    description = models.TextField(blank=True, default="")
    start_time = models.DateTimeField()
    end_time = models.DateTimeField()
    capacity = models.PositiveIntegerField(default=20)
    enrolled_count = models.PositiveIntegerField(default=0)
    waitlist_count = models.PositiveIntegerField(default=0)
    status = models.CharField(
        max_length=20,
        choices=Status.choices,
        default=Status.SCHEDULED,
    )
    recurrence_type = models.CharField(
        max_length=10,
        choices=RecurrenceType.choices,
        default=RecurrenceType.ONE_TIME,
    )
    allow_waitlist = models.BooleanField(default=True)
    notes = models.TextField(blank=True, default="")
    is_recurring = models.BooleanField(default=False)
    recurrence_rule = models.CharField(
        max_length=255,
        blank=True,
        null=True,
        help_text="RRULE string for recurring sessions",
    )
    cancel_reason = models.TextField(blank=True, default="")
    substitute_instructor = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        related_name="substitute_sessions",
        blank=True,
        null=True,
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["-start_time"]

    def save(self, *args, **kwargs):
        if not self.short_id:
            for _ in range(10):
                sid = generate_short_id()
                if not ClassSession.objects.filter(short_id=sid).exists():
                    self.short_id = sid
                    break
        super().save(*args, **kwargs)

    def __str__(self):
        return f"{self.title} - {self.start_time:%Y-%m-%d %H:%M}"


# ---------------------------------------------------------------------------
# ClassBooking
# ---------------------------------------------------------------------------
class ClassBooking(models.Model):
    class Status(models.TextChoices):
        BOOKED = "booked", "Booked"
        WAITLISTED = "waitlisted", "Waitlisted"
        ATTENDED = "attended", "Attended"
        NO_SHOW = "no_show", "No Show"
        CANCELLED = "cancelled", "Cancelled"

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    short_id = models.CharField(max_length=6, unique=True, default=generate_short_id)
    class_session = models.ForeignKey(
        ClassSession,
        on_delete=models.CASCADE,
        related_name="bookings",
    )
    member = models.ForeignKey(
        "members.MemberProfile",
        on_delete=models.CASCADE,
        related_name="class_bookings",
    )
    status = models.CharField(
        max_length=20,
        choices=Status.choices,
        default=Status.BOOKED,
    )
    booked_at = models.DateTimeField(auto_now_add=True)
    cancelled_at = models.DateTimeField(blank=True, null=True)
    checked_in_at = models.DateTimeField(blank=True, null=True)
    waitlist_position = models.PositiveIntegerField(blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["-booked_at"]
        unique_together = [("class_session", "member")]

    def save(self, *args, **kwargs):
        if not self.short_id:
            for _ in range(10):
                sid = generate_short_id()
                if not ClassBooking.objects.filter(short_id=sid).exists():
                    self.short_id = sid
                    break
        super().save(*args, **kwargs)

    def __str__(self):
        return f"{self.member} - {self.class_session} ({self.status})"


# ---------------------------------------------------------------------------
# RecurringClassTemplate
# ---------------------------------------------------------------------------
class RecurringClassTemplate(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    class_type = models.ForeignKey(
        ClassType,
        on_delete=models.CASCADE,
        related_name="recurring_templates",
    )
    instructor = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="recurring_templates",
    )
    room = models.ForeignKey(
        Room,
        on_delete=models.SET_NULL,
        related_name="recurring_templates",
        blank=True,
        null=True,
    )
    location = models.ForeignKey(
        "core.Location",
        on_delete=models.CASCADE,
        related_name="recurring_templates",
    )
    day_of_week = models.IntegerField(
        help_text="Day of week: 0=Monday, 6=Sunday",
    )
    start_time = models.TimeField()
    end_time = models.TimeField()
    capacity = models.PositiveIntegerField(default=20)
    is_active = models.BooleanField(default=True)
    effective_from = models.DateField()
    effective_until = models.DateField(blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["day_of_week", "start_time"]

    def __str__(self):
        days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
        day_name = days[self.day_of_week] if 0 <= self.day_of_week <= 6 else "?"
        return f"{self.class_type} - {day_name} {self.start_time:%H:%M}"


# ---------------------------------------------------------------------------
# VirtualClassSession
# ---------------------------------------------------------------------------
class VirtualClassSession(models.Model):
    class Platform(models.TextChoices):
        ZOOM = "zoom", "Zoom"
        GOOGLE_MEET = "google_meet", "Google Meet"
        TEAMS = "teams", "Microsoft Teams"
        CUSTOM = "custom", "Custom"

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    class_session = models.OneToOneField(
        ClassSession,
        on_delete=models.CASCADE,
        related_name="virtual_session",
    )
    platform = models.CharField(
        max_length=20,
        choices=Platform.choices,
        default=Platform.ZOOM,
    )
    meeting_url = models.URLField(max_length=500)
    meeting_id = models.CharField(max_length=100, blank=True, default="")
    recording_url = models.URLField(max_length=500, blank=True, null=True)
    is_live = models.BooleanField(default=False)
    max_online_participants = models.PositiveIntegerField(default=100)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name = "virtual class session"
        verbose_name_plural = "virtual class sessions"

    def __str__(self):
        return f"Virtual: {self.class_session} ({self.platform})"


# ---------------------------------------------------------------------------
# ClassAttendanceLog
# ---------------------------------------------------------------------------
class ClassAttendanceLog(models.Model):
    class Method(models.TextChoices):
        MANUAL = "manual", "Manual"
        QR = "qr", "QR Code"
        APP = "app", "App"

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    class_session = models.ForeignKey(
        ClassSession,
        on_delete=models.CASCADE,
        related_name="attendance_logs",
    )
    member = models.ForeignKey(
        "members.MemberProfile",
        on_delete=models.CASCADE,
        related_name="class_attendance_logs",
    )
    check_in_time = models.DateTimeField()
    check_out_time = models.DateTimeField(blank=True, null=True)
    method = models.CharField(
        max_length=10,
        choices=Method.choices,
        default=Method.MANUAL,
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["-check_in_time"]

    def __str__(self):
        return f"{self.member} checked in at {self.check_in_time:%H:%M}"


# ---------------------------------------------------------------------------
# WaitlistEntry
# ---------------------------------------------------------------------------
class WaitlistEntry(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    class_session = models.ForeignKey(
        ClassSession,
        on_delete=models.CASCADE,
        related_name="waitlist_entries",
    )
    member = models.ForeignKey(
        "members.MemberProfile",
        on_delete=models.CASCADE,
        related_name="waitlist_entries",
    )
    position = models.PositiveIntegerField()
    joined_at = models.DateTimeField(auto_now_add=True)
    notified = models.BooleanField(default=False)
    notification_sent_at = models.DateTimeField(blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name_plural = "waitlist entries"
        ordering = ["class_session", "position"]
        unique_together = [("class_session", "member")]

    def __str__(self):
        return f"{self.member} - position {self.position} for {self.class_session}"
