import logging
import os
import time
from typing import Optional, Tuple
from PIL import Image, ImageOps
import json

from .display_manager import DisplayManager

logger = logging.getLogger(__name__)

class StaticImageManager:
    """
    Manager for displaying static images on the LED matrix.
    Supports image scaling, transparency, and configurable display duration.
    """
    
    def __init__(self, display_manager: DisplayManager, config: dict):
        self.display_manager = display_manager
        self.config = config.get('static_image', {})
        
        # Configuration
        self.enabled = self.config.get('enabled', False)
        self.image_path = self.config.get('image_path', '')
        # Get display duration from main display_durations block
        self.display_duration = config.get('display', {}).get('display_durations', {}).get('static_image', 10)
        self.fit_to_display = self.config.get('fit_to_display', True)  # Auto-fit to display dimensions
        self.preserve_aspect_ratio = self.config.get('preserve_aspect_ratio', True)
        self.background_color = tuple(self.config.get('background_color', [0, 0, 0]))
        
        # State
        self.current_image = None
        self.image_loaded = False
        self.last_update_time = 0
        
        # Load initial image if enabled
        if self.enabled and self.image_path:
            self._load_image()
    
    def _load_image(self) -> bool:
        """
        Load and process the image for display.
        Returns True if successful, False otherwise.
        """
        if not self.image_path or not os.path.exists(self.image_path):
            logger.warning(f"[Static Image] Image file not found: {self.image_path}")
            return False
        
        try:
            # Load the image
            img = Image.open(self.image_path)
            
            # Convert to RGBA to handle transparency
            if img.mode != 'RGBA':
                img = img.convert('RGBA')
            
            # Get display dimensions
            display_width = self.display_manager.matrix.width
            display_height = self.display_manager.matrix.height
            
            # Calculate target size - always fit to display while preserving aspect ratio
            target_size = self._calculate_fit_size(img.size, (display_width, display_height))
            
            # Resize image
            if self.preserve_aspect_ratio:
                img = img.resize(target_size, Image.Resampling.LANCZOS)
            else:
                img = img.resize((display_width, display_height), Image.Resampling.LANCZOS)
            
            # Create display-sized canvas with background color
            canvas = Image.new('RGB', (display_width, display_height), self.background_color)
            
            # Calculate position to center the image
            paste_x = (display_width - img.width) // 2
            paste_y = (display_height - img.height) // 2
            
            # Handle transparency by compositing
            if img.mode == 'RGBA':
                # Create a temporary image with the background color
                temp_canvas = Image.new('RGB', (display_width, display_height), self.background_color)
                temp_canvas.paste(img, (paste_x, paste_y), img)
                canvas = temp_canvas
            else:
                canvas.paste(img, (paste_x, paste_y))
            
            self.current_image = canvas
            self.image_loaded = True
            self.last_update_time = time.time()
            
            logger.info(f"[Static Image] Successfully loaded and processed image: {self.image_path}")
            logger.info(f"[Static Image] Original size: {Image.open(self.image_path).size}, "
                       f"Display size: {target_size}, Position: ({paste_x}, {paste_y})")
            
            return True
            
        except Exception as e:
            logger.error(f"[Static Image] Error loading image {self.image_path}: {e}")
            self.image_loaded = False
            return False
    
    def _calculate_fit_size(self, image_size: Tuple[int, int], display_size: Tuple[int, int]) -> Tuple[int, int]:
        """
        Calculate the size to fit an image within display bounds while preserving aspect ratio.
        """
        img_width, img_height = image_size
        display_width, display_height = display_size
        
        # Calculate scaling factor to fit within display
        scale_x = display_width / img_width
        scale_y = display_height / img_height
        scale = min(scale_x, scale_y)
        
        return (int(img_width * scale), int(img_height * scale))
    
    def update(self):
        """
        Update method - no continuous updates needed for static images.
        """
        pass
    
    def display(self, force_clear: bool = False):
        """
        Display the static image on the LED matrix.
        """
        if not self.enabled or not self.image_loaded or not self.current_image:
            if self.enabled:
                logger.warning("[Static Image] Manager enabled but no image loaded")
            return
        
        # Clear display if requested
        if force_clear:
            self.display_manager.clear()
        
        # Set the image on the display manager
        self.display_manager.image = self.current_image.copy()
        
        # Update the display
        self.display_manager.update_display()
        
        logger.debug(f"[Static Image] Displayed image: {self.image_path}")
    
    def set_image_path(self, image_path: str) -> bool:
        """
        Set a new image path and load it.
        Returns True if successful, False otherwise.
        """
        self.image_path = image_path
        return self._load_image()
    
    def set_fit_to_display(self, fit_to_display: bool):
        """
        Set the fit to display option and reload the image.
        """
        self.fit_to_display = fit_to_display
        if self.image_path:
            self._load_image()
        logger.info(f"[Static Image] Fit to display set to: {self.fit_to_display}")
    
    def set_display_duration(self, duration: int):
        """
        Set the display duration in seconds.
        """
        self.display_duration = max(1, duration)  # Minimum 1 second
        logger.info(f"[Static Image] Display duration set to: {self.display_duration} seconds")
    
    def set_background_color(self, color: Tuple[int, int, int]):
        """
        Set the background color and reload the image.
        """
        self.background_color = color
        if self.image_path:
            self._load_image()
        logger.info(f"[Static Image] Background color set to: {self.background_color}")
    
    def get_image_info(self) -> dict:
        """
        Get information about the currently loaded image.
        """
        if not self.image_loaded or not self.current_image:
            return {"loaded": False}
        
        return {
            "loaded": True,
            "path": self.image_path,
            "display_size": self.current_image.size,
            "fit_to_display": self.fit_to_display,
            "display_duration": self.display_duration,
            "background_color": self.background_color
        }
    
    def reload_image(self) -> bool:
        """
        Reload the current image.
        """
        if not self.image_path:
            logger.warning("[Static Image] No image path set for reload")
            return False
        
        return self._load_image()
    
    def is_enabled(self) -> bool:
        """
        Check if the manager is enabled.
        """
        return self.enabled
    
    def get_display_duration(self) -> int:
        """
        Get the display duration in seconds.
        """
        return self.display_duration
