"""
Image optimization utility for compressing and resizing images before serving to frontend.
Reduces file size while maintaining visual quality.
"""
from PIL import Image, ImageOps
import io
from typing import Optional, Tuple
from enum import Enum
from ...shared.config.logging_config import get_logger

logger = get_logger(__name__)


class ImageType(Enum):
    """Image types with different optimization settings"""
    AVATAR = "avatar"  # Small profile images
    BANNER = "banner"  # Large banner images
    ROOM = "room"  # Room gallery images
    BLOG = "blog"  # Blog post images
    PAGE_CONTENT = "page_content"  # General page content images
    COMPANY = "company"  # Company logos/favicons
    GALLERY = "gallery"  # General gallery images


# Optimization settings for different image types
IMAGE_OPTIMIZATION_CONFIG = {
    ImageType.AVATAR: {
        "max_width": 400,
        "max_height": 400,
        "quality": 85,
        "convert_to_webp": True,
        "webp_quality": 80,
    },
    ImageType.BANNER: {
        "max_width": 1920,
        "max_height": 1080,
        "quality": 85,
        "convert_to_webp": True,
        "webp_quality": 82,
    },
    ImageType.ROOM: {
        "max_width": 1920,
        "max_height": 1920,
        "quality": 85,
        "convert_to_webp": True,
        "webp_quality": 85,
    },
    ImageType.BLOG: {
        "max_width": 1920,
        "max_height": 1920,
        "quality": 85,
        "convert_to_webp": True,
        "webp_quality": 85,
    },
    ImageType.PAGE_CONTENT: {
        "max_width": 1920,
        "max_height": 1920,
        "quality": 85,
        "convert_to_webp": True,
        "webp_quality": 85,
    },
    ImageType.COMPANY: {
        "max_width": 512,
        "max_height": 512,
        "quality": 90,
        "convert_to_webp": True,
        "webp_quality": 88,
    },
    ImageType.GALLERY: {
        "max_width": 1920,
        "max_height": 1920,
        "quality": 85,
        "convert_to_webp": True,
        "webp_quality": 85,
    },
}


def optimize_image(
    image_bytes: bytes,
    image_type: ImageType,
    preserve_original_format: bool = False
) -> Tuple[bytes, str]:
    """
    Optimize an image by resizing, compressing, and optionally converting to WebP.
    
    Args:
        image_bytes: Original image as bytes
        image_type: Type of image (determines optimization settings)
        preserve_original_format: If True, keep original format. If False, convert to WebP when beneficial.
    
    Returns:
        Tuple of (optimized_image_bytes, file_extension)
    """
    try:
        # Get optimization config for this image type
        config = IMAGE_OPTIMIZATION_CONFIG.get(image_type, IMAGE_OPTIMIZATION_CONFIG[ImageType.GALLERY])
        
        # Open and process image
        img = Image.open(io.BytesIO(image_bytes))
        
        # Convert to RGB if necessary (removes transparency, necessary for JPEG)
        # For WebP, we can preserve transparency if original format supports it
        original_format = img.format
        has_transparency = img.mode in ('RGBA', 'LA', 'P') and 'transparency' in img.info
        
        # Auto-orient image based on EXIF data
        try:
            img = ImageOps.exif_transpose(img)
        except Exception:
            # If EXIF orientation fails, continue with original image
            pass
        
        # Calculate new dimensions while maintaining aspect ratio
        width, height = img.size
        max_width = config["max_width"]
        max_height = config["max_height"]
        
        if width > max_width or height > max_height:
            # Calculate scaling factor
            scale = min(max_width / width, max_height / height)
            new_width = int(width * scale)
            new_height = int(height * scale)
            
            # Use high-quality resampling for downscaling
            # Fallback for older Pillow versions
            try:
                resampling = Image.Resampling.LANCZOS
            except AttributeError:
                resampling = Image.LANCZOS
            img = img.resize((new_width, new_height), resampling)
            logger.debug(
                f"Resized image from {width}x{height} to {new_width}x{new_height} "
                f"(scale: {scale:.2f})"
            )
        
        # Decide on output format
        output_format = original_format or 'JPEG'
        output_extension = '.jpg'
        
        # Convert to WebP if configured and beneficial
        if config.get("convert_to_webp", True) and not preserve_original_format:
            # WebP typically provides 25-35% better compression
            output_format = 'WEBP'
            output_extension = '.webp'
            
            # Preserve transparency for WebP if original had it
            if has_transparency:
                img = img.convert('RGBA')
            else:
                img = img.convert('RGB')
        else:
            # For JPEG/other formats, convert to RGB (removes transparency)
            if output_format in ('JPEG', 'JPG'):
                if img.mode != 'RGB':
                    # Create white background for images with transparency
                    if img.mode in ('RGBA', 'LA'):
                        background = Image.new('RGB', img.size, (255, 255, 255))
                        if img.mode == 'RGBA':
                            background.paste(img, mask=img.split()[3])  # Use alpha channel as mask
                        else:
                            background.paste(img)
                        img = background
                    else:
                        img = img.convert('RGB')
            
            # Keep original format extension
            if original_format:
                output_extension = f'.{original_format.lower()}'
        
        # Compress and save to bytes
        output = io.BytesIO()
        
        if output_format == 'WEBP':
            quality = config.get("webp_quality", 85)
            img.save(
                output,
                format='WEBP',
                quality=quality,
                method=6  # Method 6 is slower but produces better compression
            )
        elif output_format in ('JPEG', 'JPG'):
            quality = config.get("quality", 85)
            img.save(
                output,
                format='JPEG',
                quality=quality,
                optimize=True,  # Enable JPEG optimization
                progressive=True  # Progressive JPEG for better perceived loading
            )
        elif output_format == 'PNG':
            # PNG compression
            img.save(
                output,
                format='PNG',
                optimize=True,
                compress_level=9  # Maximum compression (0-9)
            )
        else:
            # For other formats (GIF, etc.), save as-is with optimization
            img.save(output, format=output_format, optimize=True)
        
        optimized_bytes = output.getvalue()
        
        # Log optimization results
        original_size = len(image_bytes)
        optimized_size = len(optimized_bytes)
        reduction_percent = ((original_size - optimized_size) / original_size * 100) if original_size > 0 else 0
        
        logger.info(
            f"Image optimized: {original_size} bytes -> {optimized_size} bytes "
            f"({reduction_percent:.1f}% reduction, type: {image_type.value})"
        )
        
        return optimized_bytes, output_extension
        
    except Exception as e:
        logger.error(f"Error optimizing image: {str(e)}", exc_info=True)
        # Return original image if optimization fails
        logger.warning("Returning original image due to optimization error")
        original_format = Image.open(io.BytesIO(image_bytes)).format or 'JPEG'
        extension = f'.{original_format.lower()}' if original_format else '.jpg'
        return image_bytes, extension


async def optimize_image_async(
    image_bytes: bytes,
    image_type: ImageType,
    preserve_original_format: bool = False
) -> Tuple[bytes, str]:
    """
    Async wrapper for optimize_image (for use in async endpoints).
    
    Args:
        image_bytes: Original image as bytes
        image_type: Type of image (determines optimization settings)
        preserve_original_format: If True, keep original format. If False, convert to WebP when beneficial.
    
    Returns:
        Tuple of (optimized_image_bytes, file_extension)
    """
    import asyncio
    # Run the CPU-intensive optimization in a thread pool to avoid blocking
    loop = asyncio.get_event_loop()
    return await loop.run_in_executor(
        None,
        optimize_image,
        image_bytes,
        image_type,
        preserve_original_format
    )

