"""
Ride-specific media models for ThrillWiki.

This module contains media models specific to rides domain.
"""

from typing import Any, cast

import pghistory
from django.conf import settings
from django.db import models

from apps.core.choices import RichChoiceField
from apps.core.history import TrackedModel
from apps.core.services.media_service import MediaService


def ride_photo_upload_path(instance: models.Model, filename: str) -> str:
    """Generate upload path for ride photos."""
    photo = cast("RidePhoto", instance)
    ride = photo.ride

    if ride is None:
        raise ValueError("Ride cannot be None")

    return MediaService.generate_upload_path(
        domain="park",
        identifier=ride.slug,
        filename=filename,
        subdirectory=ride.park.slug,
    )


@pghistory.track()
class RidePhoto(TrackedModel):
    """Photo model specific to rides."""

    ride = models.ForeignKey("rides.Ride", on_delete=models.CASCADE, related_name="photos")

    image = models.ForeignKey(
        "django_cloudflareimages_toolkit.CloudflareImage",
        on_delete=models.CASCADE,
        help_text="Ride photo stored on Cloudflare Images",
    )

    caption = models.CharField(max_length=255, blank=True)
    photographer = models.CharField(
        max_length=200,
        blank=True,
        help_text="Photographer credit (maps to frontend photographer_credit)"
    )
    alt_text = models.CharField(max_length=255, blank=True)
    is_primary = models.BooleanField(default=False)
    is_approved = models.BooleanField(default=False)

    # Ride-specific metadata
    photo_type = RichChoiceField(
        choice_group="photo_types",
        domain="rides",
        max_length=50,
        default="exterior",
        help_text="Type of photo for categorization and display purposes",
    )

    # Metadata
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    date_taken = models.DateTimeField(null=True, blank=True)

    # User who uploaded the photo
    uploaded_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        related_name="uploaded_ride_photos",
    )

    class Meta(TrackedModel.Meta):
        app_label = "rides"
        ordering = ["-is_primary", "-created_at"]
        indexes = [
            models.Index(fields=["ride", "is_primary"]),
            models.Index(fields=["ride", "is_approved"]),
            models.Index(fields=["ride", "photo_type"]),
            models.Index(fields=["created_at"]),
        ]
        constraints = [
            # Only one primary photo per ride
            models.UniqueConstraint(
                fields=["ride"],
                condition=models.Q(is_primary=True),
                name="unique_primary_ride_photo",
            )
        ]

    def __str__(self) -> str:
        return f"Photo of {self.ride.name} - {self.caption or 'No caption'}"

    def save(self, *args: Any, **kwargs: Any) -> None:
        # Extract EXIF date if this is a new photo
        if not self.pk and not self.date_taken and self.image:
            self.date_taken = MediaService.extract_exif_date(self.image)

        # Set default caption if not provided
        if not self.caption and self.uploaded_by:
            self.caption = MediaService.generate_default_caption(self.uploaded_by.username)

        # If this is marked as primary, unmark other primary photos for this ride
        if self.is_primary:
            RidePhoto.objects.filter(
                ride=self.ride,
                is_primary=True,
            ).exclude(
                pk=self.pk
            ).update(is_primary=False)

        super().save(*args, **kwargs)

    @property
    def file_size(self) -> int | None:
        """Get file size in bytes."""
        try:
            return self.image.size
        except (ValueError, OSError):
            return None

    @property
    def dimensions(self) -> list[int] | None:
        """Get image dimensions as [width, height]."""
        try:
            return [self.image.width, self.image.height]
        except (ValueError, OSError):
            return None

    def get_absolute_url(self) -> str:
        """Get absolute URL for this photo."""
        return f"/parks/{self.ride.park.slug}/rides/{self.ride.slug}/photos/{self.pk}/"

    @property
    def park(self):
        """Get the park this ride belongs to."""
        return self.ride.park
