import os

from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.utils.text import slugify
from PIL import Image as PILImage
from .base import validate_image_size


def get_image_upload_path(instance, filename):
    """
    Generate upload path for images based on the image library structure.
    """
    return f"image_library/{filename}"


class ImageLibrary(models.Model):
    """
    Generic image library model that can be referenced by other models
    to avoid duplicate uploads and provide centralized image management.
    """

    # Image metadata
    name = models.CharField(max_length=200, help_text="Descriptive name for the image")
    slug = models.SlugField(
        max_length=250, unique=True, help_text="URL-friendly version of the name"
    )
    description = models.TextField(
        blank=True, help_text="Optional description of the image"
    )
    alt_text = models.CharField(
        max_length=255, help_text="Alternative text for accessibility"
    )

    # Image file
    image = models.ImageField(
        upload_to=get_image_upload_path,
        validators=[validate_image_size],
        help_text="Upload image file (max 1MB)",
    )

    # Image properties (automatically populated)
    width = models.PositiveIntegerField(
        null=True, blank=True, help_text="Image width in pixels"
    )
    height = models.PositiveIntegerField(
        null=True, blank=True, help_text="Image height in pixels"
    )
    file_size = models.PositiveIntegerField(
        null=True, blank=True, help_text="File size in bytes"
    )

    # Categorization
    CATEGORY_CHOICES = [
        ("logo", "Logo"),
        ("article", "Article Image"),
        ("banner", "Banner"),
        ("icon", "Icon"),
        ("screenshot", "Screenshot"),
        ("photo", "Photo"),
        ("other", "Other"),
    ]
    category = models.CharField(
        max_length=20,
        choices=CATEGORY_CHOICES,
        default="other",
        help_text="Category of the image",
    )

    # Tags for easier searching
    tags = models.CharField(
        max_length=500, blank=True, help_text="Comma-separated tags for searching"
    )

    # Metadata
    uploaded_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        help_text="User who uploaded the image",
    )
    uploaded_at = models.DateTimeField(
        auto_now_add=True, help_text="Date and time when image was uploaded"
    )
    updated_at = models.DateTimeField(
        auto_now=True, help_text="Date and time when image was last updated"
    )

    # Usage tracking
    usage_count = models.PositiveIntegerField(
        default=0, help_text="Number of times this image is referenced"
    )

    class Meta:
        ordering = ["-uploaded_at"]
        verbose_name = "Image"
        verbose_name_plural = "Image Library"

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        """
        Override save to automatically populate image properties and slug.
        """
        # Generate slug if not provided
        if not self.slug:
            self.slug = slugify(self.name)

        # Save the model first to get the image file
        super().save(*args, **kwargs)

        # Update image properties if image exists
        if self.image:
            self._update_image_properties()

    def _update_image_properties(self):
        """
        Update image properties like width, height, and file size.
        """
        try:
            # Get image dimensions
            with PILImage.open(self.image.path) as img:
                self.width = img.width
                self.height = img.height

            # Get file size
            self.file_size = self.image.size

            # Save without calling the full save method to avoid recursion
            ImageLibrary.objects.filter(pk=self.pk).update(
                width=self.width, height=self.height, file_size=self.file_size
            )
        except Exception as e:
            # Log error but don't fail the save
            print(f"Error updating image properties: {e}")

    def get_file_size_display(self):
        """
        Return human-readable file size.
        """
        if not self.file_size:
            return "Unknown"

        size = self.file_size
        for unit in ["B", "KB", "MB", "GB"]:
            if size < 1024.0:
                return f"{size:.1f} {unit}"
            size /= 1024.0
        return f"{size:.1f} TB"

    def get_tags_list(self):
        """
        Return tags as a list.
        """
        if not self.tags:
            return []
        return [tag.strip() for tag in self.tags.split(",") if tag.strip()]

    def increment_usage(self):
        """
        Increment usage count when image is referenced.
        """
        self.usage_count += 1
        self.save(update_fields=["usage_count"])

    def decrement_usage(self):
        """
        Decrement usage count when reference is removed.
        """
        if self.usage_count > 0:
            self.usage_count -= 1
            self.save(update_fields=["usage_count"])


class ImageReference(models.Model):
    """
    Abstract base class for models that want to reference images from the library.
    This helps track usage and provides a consistent interface.
    """

    image_library = models.ForeignKey(
        ImageLibrary,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        help_text="Select an image from the library",
        related_name="%(class)s_references",
    )

    class Meta:
        abstract = True

    def save(self, *args, **kwargs):
        """
        Override save to update usage count.
        """
        # Track if image changed
        old_image = None
        if self.pk:
            try:
                old_instance = self.__class__.objects.get(pk=self.pk)
                old_image = old_instance.image_library
            except self.__class__.DoesNotExist:
                pass

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

        # Update usage counts
        if old_image and old_image != self.image_library:
            old_image.decrement_usage()

        if self.image_library and self.image_library != old_image:
            self.image_library.increment_usage()

    def delete(self, *args, **kwargs):
        """
        Override delete to update usage count.
        """
        if self.image_library:
            self.image_library.decrement_usage()
        super().delete(*args, **kwargs)
