"""
Linux BenchTools - Image Processor
Handles image compression, resizing and thumbnail generation
"""

import os
from pathlib import Path
from typing import Tuple, Optional
from PIL import Image
import hashlib
from datetime import datetime

from app.core.config import settings
from app.utils.image_config_loader import image_compression_config


class ImageProcessor:
    """Image processing utilities"""

    @staticmethod
    def process_image_with_level(
        image_path: str,
        output_dir: str,
        compression_level: Optional[str] = None,
        output_format: Optional[str] = None,
        save_original: bool = True
    ) -> Tuple[str, int, Optional[str]]:
        """
        Process an image using configured compression level
        Saves original in original/ subdirectory and resized in main directory

        Args:
            image_path: Path to source image
            output_dir: Directory for output
            compression_level: Compression level (high, medium, low, minimal)
                             If None, uses default from config
            output_format: Output format (None = PNG from config)
            save_original: Save original file in original/ subdirectory

        Returns:
            Tuple of (output_path, file_size_bytes, original_path)
        """
        # Get compression settings and folders config
        level_config = image_compression_config.get_level(compression_level)
        folders = image_compression_config.get_folders()

        if output_format is None:
            output_format = image_compression_config.get_output_format()

        # Create subdirectories
        original_dir = os.path.join(output_dir, folders.get("original", "original"))
        os.makedirs(original_dir, exist_ok=True)
        os.makedirs(output_dir, exist_ok=True)

        # Save original if requested
        original_path = None
        if save_original and image_compression_config.should_keep_original():
            import shutil
            original_filename = os.path.basename(image_path)
            original_path = os.path.join(original_dir, original_filename)
            shutil.copy2(image_path, original_path)

        # Process and resize image
        resized_path, file_size = ImageProcessor.process_image(
            image_path=image_path,
            output_dir=output_dir,
            max_width=level_config.get("max_width"),
            max_height=level_config.get("max_height"),
            quality=level_config.get("quality"),
            output_format=output_format
        )

        return resized_path, file_size, original_path

    @staticmethod
    def create_thumbnail_with_level(
        image_path: str,
        output_dir: str,
        compression_level: Optional[str] = None,
        output_format: Optional[str] = None
    ) -> Tuple[str, int]:
        """
        Create thumbnail using configured compression level
        Saves in thumbnail/ subdirectory

        Args:
            image_path: Path to source image
            output_dir: Directory for output
            compression_level: Compression level (high, medium, low, minimal)
            output_format: Output format (None = PNG from config)

        Returns:
            Tuple of (output_path, file_size_bytes)
        """
        # Get compression settings and folders config
        level_config = image_compression_config.get_level(compression_level)
        folders = image_compression_config.get_folders()

        if output_format is None:
            output_format = image_compression_config.get_output_format()

        # Create thumbnail subdirectory
        thumbnail_dir = os.path.join(output_dir, folders.get("thumbnail", "thumbnail"))
        os.makedirs(thumbnail_dir, exist_ok=True)

        return ImageProcessor.create_thumbnail(
            image_path=image_path,
            output_dir=thumbnail_dir,
            size=level_config.get("thumbnail_size"),
            quality=level_config.get("thumbnail_quality"),
            output_format=output_format
        )

    @staticmethod
    def process_image(
        image_path: str,
        output_dir: str,
        max_width: Optional[int] = None,
        max_height: Optional[int] = None,
        quality: Optional[int] = None,
        output_format: str = "webp"
    ) -> Tuple[str, int]:
        """
        Process an image: resize and compress

        Args:
            image_path: Path to source image
            output_dir: Directory for output
            max_width: Maximum width (None = no limit)
            max_height: Maximum height (None = no limit)
            quality: Compression quality 1-100 (None = use settings)
            output_format: Output format (webp, jpeg, png)

        Returns:
            Tuple of (output_path, file_size_bytes)
        """
        # Use settings if not provided
        if max_width is None:
            max_width = settings.IMAGE_MAX_WIDTH
        if max_height is None:
            max_height = settings.IMAGE_MAX_HEIGHT
        if quality is None:
            quality = settings.IMAGE_COMPRESSION_QUALITY

        # Open image
        img = Image.open(image_path)

        # Convert RGBA to RGB for JPEG/WebP
        if img.mode == 'RGBA' and output_format.lower() in ['jpeg', 'jpg', 'webp']:
            # Create white background
            background = Image.new('RGB', img.size, (255, 255, 255))
            background.paste(img, mask=img.split()[3])  # Use alpha channel as mask
            img = background

        # Resize if needed
        original_width, original_height = img.size
        if max_width and original_width > max_width or max_height and original_height > max_height:
            img.thumbnail((max_width or original_width, max_height or original_height), Image.Resampling.LANCZOS)

        # Generate unique filename
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        original_name = Path(image_path).stem
        output_filename = f"{original_name}_{timestamp}.{output_format}"
        output_path = os.path.join(output_dir, output_filename)

        # Ensure output directory exists
        os.makedirs(output_dir, exist_ok=True)

        # Save with compression
        save_kwargs = {'quality': quality, 'optimize': True}

        if output_format.lower() == 'webp':
            save_kwargs['method'] = 6  # Better compression
        elif output_format.lower() in ['jpeg', 'jpg']:
            save_kwargs['progressive'] = True

        img.save(output_path, format=output_format.upper(), **save_kwargs)

        # Get file size
        file_size = os.path.getsize(output_path)

        return output_path, file_size

    @staticmethod
    def create_thumbnail(
        image_path: str,
        output_dir: str,
        size: Optional[int] = None,
        quality: Optional[int] = None,
        output_format: Optional[str] = None
    ) -> Tuple[str, int]:
        """
        Create a thumbnail

        Args:
            image_path: Path to source image
            output_dir: Directory for output
            size: Thumbnail size (square, None = use settings)
            quality: Compression quality (None = use settings)
            output_format: Output format (None = use settings)

        Returns:
            Tuple of (output_path, file_size_bytes)
        """
        # Use settings if not provided
        if size is None:
            size = settings.THUMBNAIL_SIZE
        if quality is None:
            quality = settings.THUMBNAIL_QUALITY
        if output_format is None:
            output_format = settings.THUMBNAIL_FORMAT

        # Open image
        img = Image.open(image_path)

        # Convert RGBA to RGB for JPEG/WebP
        if img.mode == 'RGBA' and output_format.lower() in ['jpeg', 'jpg', 'webp']:
            background = Image.new('RGB', img.size, (255, 255, 255))
            background.paste(img, mask=img.split()[3])
            img = background

        # Resize keeping aspect ratio (width-based)
        # size parameter represents the target width
        width, height = img.size
        aspect_ratio = height / width
        new_width = size
        new_height = int(size * aspect_ratio)

        # Use thumbnail method to preserve aspect ratio
        img.thumbnail((new_width, new_height), Image.Resampling.LANCZOS)

        # Generate filename
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        original_name = Path(image_path).stem
        output_filename = f"{original_name}_thumb_{timestamp}.{output_format}"
        output_path = os.path.join(output_dir, output_filename)

        # Ensure output directory exists
        os.makedirs(output_dir, exist_ok=True)

        # Save
        save_kwargs = {'quality': quality, 'optimize': True}

        if output_format.lower() == 'webp':
            save_kwargs['method'] = 6
        elif output_format.lower() in ['jpeg', 'jpg']:
            save_kwargs['progressive'] = True

        img.save(output_path, format=output_format.upper(), **save_kwargs)

        # Get file size
        file_size = os.path.getsize(output_path)

        return output_path, file_size

    @staticmethod
    def get_image_hash(image_path: str) -> str:
        """
        Calculate SHA256 hash of image file

        Args:
            image_path: Path to image

        Returns:
            SHA256 hash as hex string
        """
        sha256_hash = hashlib.sha256()

        with open(image_path, "rb") as f:
            # Read in chunks for large files
            for byte_block in iter(lambda: f.read(4096), b""):
                sha256_hash.update(byte_block)

        return sha256_hash.hexdigest()

    @staticmethod
    def get_image_info(image_path: str) -> dict:
        """
        Get image information

        Args:
            image_path: Path to image

        Returns:
            Dictionary with image info
        """
        img = Image.open(image_path)

        return {
            "width": img.width,
            "height": img.height,
            "format": img.format,
            "mode": img.mode,
            "size_bytes": os.path.getsize(image_path),
            "hash": ImageProcessor.get_image_hash(image_path)
        }

    @staticmethod
    def is_valid_image(file_path: str) -> bool:
        """
        Check if file is a valid image

        Args:
            file_path: Path to file

        Returns:
            True if valid image, False otherwise
        """
        try:
            img = Image.open(file_path)
            img.verify()
            return True
        except Exception:
            return False

    @staticmethod
    def get_mime_type(file_path: str) -> Optional[str]:
        """
        Get MIME type from image file

        Args:
            file_path: Path to image

        Returns:
            MIME type string or None
        """
        try:
            img = Image.open(file_path)
            format_to_mime = {
                'JPEG': 'image/jpeg',
                'PNG': 'image/png',
                'GIF': 'image/gif',
                'BMP': 'image/bmp',
                'WEBP': 'image/webp',
                'TIFF': 'image/tiff'
            }
            return format_to_mime.get(img.format, f'image/{img.format.lower()}')
        except Exception:
            return None
