import os
import uuid
from io import BytesIO

from PIL import Image, ImageOps
from django.conf import settings
from django.core.files.base import ContentFile
from rest_framework import serializers

from .models import PostImages


class PostImagesSerializer(serializers.ModelSerializer):
    class Meta:
        model = PostImages
        fields = '__all__'


class PostImageCreateSerializer(serializers.Serializer):
    """
    Serializer for uploading and processing an image.
    """
    image = serializers.ImageField(write_only=True, help_text="Yüklenecek resim dosyası.")
    title = serializers.CharField(max_length=254, help_text="Resim için bir başlık.")
    width = serializers.IntegerField(help_text="Resmin yeni genişliği (pixel).")
    height = serializers.IntegerField(help_text="Resmin yeni yüksekliği (pixel).")
    quality = serializers.IntegerField(default=85, min_value=1, max_value=100, help_text="JPG/WebP için kalite (1-100).")
    format = serializers.ChoiceField(
        choices=['png', 'webp', 'jpg', 'avif'],
        default='avif',
        help_text="Çıktı resim formatı."
    )

    def create(self, validated_data):
        image_file = validated_data.pop('image')
        title = validated_data.pop('title')
        new_width = validated_data.pop('width')
        new_height = validated_data.pop('height')
        quality = validated_data.pop('quality')
        output_format = validated_data.pop('format')

        # Open the image with Pillow
        img = Image.open(image_file)

        # Preserve original metadata for the model
        original_filename = image_file.name
        original_size = image_file.size

        # Process the image: Resize and crop to fill target dimensions (Center Crop).
        # This ensures the image fills the dimensions without distortion or padding.
        
        # ImageOps.fit resizes and crops the image to the requested size.
        img = ImageOps.fit(img, (new_width, new_height), method=Image.Resampling.LANCZOS, centering=(0.5, 0.5))

        # If output format does not support transparency (like JPG), convert to RGB.
        # This also ensures compatibility for formats like JPEG that don't support P or RGBA.
        if output_format != 'png' and img.mode != 'RGB':
            img = img.convert('RGB')

        # Save the processed image to an in-memory buffer
        buffer = BytesIO()
        
        # Pillow expects 'JPEG' format identifier, not 'jpg'
        save_format = output_format.upper()
        if save_format == 'JPG':
            save_format = 'JPEG'
            
        save_kwargs = {'format': save_format}
        if output_format in ['jpg', 'webp']:
            save_kwargs['quality'] = quality
        img.save(buffer, **save_kwargs)
        buffer.seek(0)

        # Generate a unique filename and path
        new_filename = f"processed/{uuid.uuid4()}.{output_format}"
        file_path = os.path.join(settings.MEDIA_ROOT, new_filename)

        # Ensure the directory exists
        os.makedirs(os.path.dirname(file_path), exist_ok=True)

        # Save the new file to the media directory
        with open(file_path, 'wb') as f:
            f.write(buffer.getvalue())

        # Get the size of the new file
        new_size = os.path.getsize(file_path)

        # Get user from validated_data if provided (serializer.save(user=...))
        user = validated_data.pop('user', None)

        # Create the PostImages model instance
        instance = PostImages.objects.create(
            title=title,
            user=user,
            path=new_filename,  # Store the relative path
            processed_path=original_filename,  # Let's use this field for original name for now
            original_filename=original_filename,
            format=output_format,
            width=new_width,  # Use the target width
            height=new_height,  # Use the target height
            size=new_size,
            quality=quality,
        )
        return instance

    def to_representation(self, instance):
        # Use the PostImagesSerializer to represent the created object
        return PostImagesSerializer(instance).data
