from django.db import models
from django.conf import settings
from django.utils import timezone
import secrets
import time


def uuid7() -> str:
    """Generate a UUID v7 (time-ordered UUID)."""
    nanoseconds = time.time_ns()
    uuid_int = (nanoseconds << 16) | secrets.randbits(48)
    return f"{uuid_int:032x}"


class Event(models.Model):
    """Event management."""
    TYPE_CHOICES = [
        ("webinar", "Webinar"),
        ("dissemination", "Dissemination"),
        ("conference", "Conference"),
        ("workshop", "Workshop"),
        ("seminar", "Seminar"),
        ("meeting", "Meeting"),
        ("other", "Other"),
    ]
    STATUS_CHOICES = [
        ("draft", "Draft"),
        ("published", "Published"),
        ("cancelled", "Cancelled"),
        ("completed", "Completed"),
    ]

    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    name = models.CharField(max_length=255)
    event_type = models.CharField(max_length=50, default="other")
    description = models.TextField(blank=True)
    start_date = models.DateTimeField()
    end_date = models.DateTimeField()
    location = models.CharField(max_length=255, blank=True)
    organizer = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="organized_events")
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="draft")
    capacity = models.IntegerField(null=True, blank=True)
    tags = models.JSONField(default=list)
    settings = models.JSONField(default=dict)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "events"
        ordering = ["-start_date"]

    def __str__(self):
        return self.name


class EventTemplate(models.Model):
    """Reusable event templates."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    name = models.CharField(max_length=255)
    event_type = models.CharField(max_length=20, choices=Event.TYPE_CHOICES)
    description = models.TextField(blank=True)
    duration_hours = models.DecimalField(max_digits=4, decimal_places=1)
    default_settings = models.JSONField(default=dict)
    created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "event_templates"
        ordering = ["name"]


class InvitationTemplate(models.Model):
    """Reusable visual invitation card templates."""
    CATEGORY_CHOICES = [
        ("formal", "Formal Corporate"),
        ("casual", "Casual / Friendly"),
        ("reminder", "Reminder"),
        ("confirmation", "Confirmation / RSVP"),
        ("other", "Other"),
    ]

    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    name = models.CharField(max_length=255)
    category = models.CharField(max_length=20, choices=CATEGORY_CHOICES, default="formal")
    description = models.TextField(blank=True)
    design = models.JSONField(default=dict)
    thumbnail = models.ImageField(upload_to="invitation_templates/", null=True, blank=True)
    is_default = models.BooleanField(default=False)
    created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "invitation_templates"
        ordering = ["category", "name"]
        indexes = [models.Index(fields=["category"])]

    def __str__(self):
        return f"{self.name} ({self.get_category_display()})"


class EventInvitation(models.Model):
    """Event invitations/registrations."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="invitations")
    contact = models.ForeignKey(
        "contacts.Contact",
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name="event_invitations",
    )
    email = models.EmailField()
    name = models.CharField(max_length=255)
    status = models.CharField(max_length=20, choices=[
        ("pending", "Pending"),
        ("accepted", "Accepted"),
        ("declined", "Declined"),
        ("tentative", "Tentative"),
    ], default="pending")
    invited_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True)
    responded_at = models.DateTimeField(null=True, blank=True)
    check_in_time = models.DateTimeField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "event_invitations"
        ordering = ["-created_at"]
        unique_together = ["event", "email"]


class EventTeam(models.Model):
    """Event team members."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="teams")
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="event_teams")
    role = models.CharField(max_length=50, default="member")
    is_lead = models.BooleanField(default=False)
    joined_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "event_teams"
        ordering = ["-joined_at"]
        unique_together = ["event", "user"]


class EventSpeaker(models.Model):
    """Event speakers. Speaker identity = Contact (canonical Person). Flat fields kept as fallback."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="speakers")
    contact = models.ForeignKey(
        "contacts.Contact",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="event_speaker_appearances",
    )
    name = models.CharField(max_length=255)
    title = models.CharField(max_length=255, blank=True)
    organization = models.CharField(max_length=255, blank=True)
    bio = models.TextField(blank=True)
    session_title = models.CharField(max_length=255, blank=True)
    session_type = models.CharField(max_length=50, choices=[
        ("keynote", "Keynote"),
        ("panel", "Panel"),
        ("workshop", "Workshop"),
        ("break", "Break"),
        ("networking", "Networking"),
        ("plenary", "Plenary"),
        ("ceremony", "Ceremony"),
        ("other", "Other"),
    ], default="other")
    start_time = models.TimeField(null=True, blank=True)
    end_time = models.TimeField(null=True, blank=True)
    material_status = models.CharField(max_length=20, choices=[
        ("pending", "Pending"),
        ("uploaded", "Uploaded"),
        ("not_required", "Not Required"),
    ], default="pending")
    material_file = models.FileField(upload_to="speaker_materials/", null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "event_speakers"
        ordering = ["start_time", "created_at"]


class EventScheduleItem(models.Model):
    """Event schedule items."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="schedule_items")
    title = models.CharField(max_length=255)
    description = models.TextField(blank=True)
    session_type = models.CharField(max_length=50, choices=[
        ("keynote", "Keynote"),
        ("panel", "Panel"),
        ("workshop", "Workshop"),
        ("break", "Break"),
        ("networking", "Networking"),
        ("plenary", "Plenary"),
        ("ceremony", "Ceremony"),
        ("other", "Other"),
    ], default="other")
    track = models.CharField(max_length=100, default="Main Hall")
    start_time = models.TimeField()
    end_time = models.TimeField()
    speaker = models.ForeignKey(
        "contacts.Contact",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="event_schedule_appearances",
    )
    speaker_name = models.CharField(max_length=255, blank=True)
    material_file = models.CharField(max_length=255, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "event_schedule_items"
        ordering = ["start_time", "track"]


class EventRegistration(models.Model):
    """Event registrations (attendees). Attendee identity = Contact. Flat fields kept for legacy walk-ins."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="registrations")
    contact = models.ForeignKey(
        "contacts.Contact",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="event_registrations",
    )
    name = models.CharField(max_length=255)
    email = models.EmailField()
    phone = models.CharField(max_length=50, blank=True)
    company = models.CharField(max_length=255, blank=True)
    status = models.CharField(max_length=20, choices=[
        ("registered", "Registered"),
        ("checked_in", "Checked In"),
        ("rejected", "Rejected"),
    ], default="registered")
    is_vip = models.BooleanField(default=False, help_text="Flag as VVIP for priority handling.")
    check_in_time = models.DateTimeField(null=True, blank=True)
    registration_date = models.DateTimeField(auto_now_add=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "event_registrations"
        ordering = ["-registration_date"]
        unique_together = ["event", "email"]


class EventMedia(models.Model):
    """Event media (photos/videos)."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="media")
    file = models.FileField(upload_to="event_media/", null=True, blank=True)
    file_type = models.CharField(max_length=20, choices=[
        ("image", "Image"),
        ("video", "Video"),
        ("document", "Document"),
    ], default="image")
    title = models.CharField(max_length=255, blank=True)
    description = models.TextField(blank=True)
    caption = models.CharField(max_length=255, blank=True)
    is_cover = models.BooleanField(default=False)
    uploaded_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "event_media"
        ordering = ["-created_at"]


class EventDocument(models.Model):
    """Event documents."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="documents")
    name = models.CharField(max_length=255, blank=True)
    title = models.CharField(max_length=255, blank=True)
    description = models.TextField(blank=True)
    file = models.FileField(upload_to="event_documents/", null=True, blank=True)
    file_size = models.PositiveBigIntegerField(default=0)
    category = models.CharField(max_length=100, blank=True)
    uploaded_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "event_documents"
        ordering = ["-created_at"]


class RegistrationForm(models.Model):
    """Form-builder schema for collecting registrations."""
    SOURCE_CHOICES = [
        ("public", "Public"),
        ("project", "Project"),
    ]
    STATUS_CHOICES = [
        ("draft", "Draft"),
        ("published", "Published"),
        ("closed", "Closed"),
    ]

    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    name = models.CharField(max_length=255)
    description = models.TextField(blank=True)
    source = models.CharField(max_length=20, choices=SOURCE_CHOICES, default="public")
    event = models.ForeignKey(
        Event,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="registration_forms",
    )
    project = models.ForeignKey(
        "projects.Project",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="registration_forms",
    )
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="draft")
    config = models.JSONField(default=dict, blank=True)
    created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name="created_registration_forms")
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "registration_forms"
        ordering = ["-updated_at"]
        indexes = [
            models.Index(fields=["source"]),
            models.Index(fields=["status"]),
        ]

    def __str__(self):
        return self.name


class RegistrationFormField(models.Model):
    """A single field/element on a RegistrationForm."""
    TYPE_CHOICES = [
        ("header", "Header"),
        ("paragraph", "Paragraph"),
        ("section", "Section"),
        ("divider", "Divider"),
        ("text", "Short Text"),
        ("number", "Number"),
        ("email", "Email"),
        ("phone", "Phone"),
        ("yes_no", "Yes/No"),
        ("checkbox", "Checkbox"),
        ("checklist", "Checklist"),
        ("dropdown", "Dropdown"),
        ("radio", "Radio"),
        ("table", "Table"),
    ]

    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    form = models.ForeignKey(RegistrationForm, on_delete=models.CASCADE, related_name="fields")
    order = models.PositiveIntegerField(default=0)
    type = models.CharField(max_length=20, choices=TYPE_CHOICES)
    label = models.CharField(max_length=255, blank=True)
    placeholder = models.CharField(max_length=255, blank=True)
    required = models.BooleanField(default=False)
    options = models.JSONField(default=list, blank=True)
    columns = models.PositiveIntegerField(null=True, blank=True)
    meta = models.JSONField(default=dict, blank=True)

    class Meta:
        db_table = "registration_form_fields"
        ordering = ["order", "id"]
        indexes = [models.Index(fields=["form", "order"])]


class RegistrationFormSubmission(models.Model):
    """A single response submitted to a RegistrationForm."""
    STATUS_CHOICES = [
        ("pending", "Pending"),
        ("reviewed", "Reviewed"),
        ("approved", "Approved"),
        ("rejected", "Rejected"),
    ]

    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    form = models.ForeignKey(RegistrationForm, on_delete=models.CASCADE, related_name="submissions")
    submitter_name = models.CharField(max_length=255, blank=True)
    submitter_email = models.EmailField(blank=True)
    answers = models.JSONField(default=dict, blank=True)
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="pending")
    auto_blocked = models.BooleanField(default=False)
    block_reason = models.CharField(max_length=500, blank=True)
    submitted_at = models.DateTimeField(auto_now_add=True)
    reviewed_at = models.DateTimeField(null=True, blank=True)
    reviewed_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name="reviewed_form_submissions")
    ip_address = models.GenericIPAddressField(null=True, blank=True)

    class Meta:
        db_table = "registration_form_submissions"
        ordering = ["-submitted_at"]
        indexes = [
            models.Index(fields=["form", "status"]),
            models.Index(fields=["form", "submitted_at"]),
        ]


class EventBlocklist(models.Model):
    """Blocked emails. Global if event is null; else scoped to that event."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    email = models.EmailField()
    name = models.CharField(max_length=255, blank=True)
    reason = models.CharField(max_length=500, blank=True)
    event = models.ForeignKey(
        Event,
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name="blocklist_entries",
    )
    blocked_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name="created_blocklist_entries")
    blocked_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "event_blocklist"
        ordering = ["-blocked_at"]
        indexes = [
            models.Index(fields=["email"]),
            models.Index(fields=["event", "email"]),
        ]
        constraints = [
            models.UniqueConstraint(fields=["email", "event"], name="uniq_blocklist_email_event"),
        ]

    def __str__(self):
        scope = f" @ {self.event.name}" if self.event_id else " (global)"
        return f"{self.email}{scope}"


class EventLog(models.Model):
    """Event activity logs."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="logs")
    actor = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True)
    action = models.CharField(max_length=100)
    detail = models.TextField(blank=True)
    log_type = models.CharField(max_length=20, choices=[
        ("create", "Created"),
        ("file", "File"),
        ("task", "Task"),
        ("invite", "Invite"),
        ("rsvp", "RSVP"),
        ("status", "Status"),
    ], default="status")
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "event_logs"
        ordering = ["-created_at"]


DEFAULT_EVENT_SETTINGS = {
    "default_event_type": "webinar",
    "default_status": "draft",
    "default_capacity": 0,
    "default_location": "",
    "categories": [
        {"value": "webinar", "label": "Webinar"},
        {"value": "dissemination", "label": "Dissemination"},
        {"value": "conference", "label": "Conference"},
        {"value": "workshop", "label": "Workshop"},
        {"value": "seminar", "label": "Seminar"},
        {"value": "meeting", "label": "Meeting"},
        {"value": "other", "label": "Other"},
    ],
}


class OfficeCalendarEntry(models.Model):
    """Org-wide calendar dates — holidays and office events shown on the shared calendar."""

    TYPE_CHOICES = [
        ("holiday", "Holiday"),
        ("event", "Office Event"),
    ]

    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    title = models.CharField(max_length=255)
    entry_type = models.CharField(max_length=20, choices=TYPE_CHOICES, default="holiday")
    date = models.DateField()
    end_date = models.DateField(null=True, blank=True)
    recurring = models.BooleanField(default=False, help_text="Repeats yearly on the same month/day.")
    description = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "office_calendar_entry"
        ordering = ["date"]
        verbose_name = "Office calendar entry"
        verbose_name_plural = "Office calendar entries"
        indexes = [models.Index(fields=["date"])]

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


class EventSettings(models.Model):
    """Singleton holding org-wide event defaults."""

    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    settings = models.JSONField(default=dict, blank=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "event_settings"
        verbose_name = "Event settings"
        verbose_name_plural = "Event settings"

    def __str__(self):
        return "Event settings"

    @classmethod
    def get_solo(cls) -> "EventSettings":
        obj = cls.objects.first()
        if obj is None:
            obj = cls.objects.create(settings=DEFAULT_EVENT_SETTINGS)
        elif not obj.settings:
            obj.settings = DEFAULT_EVENT_SETTINGS
            obj.save(update_fields=["settings", "updated_at"])
        return obj