from PIL import Image, ImageDraw
from typing import Dict, Optional, Tuple


class SelectionArea:
    """Class to handle selected rectangular areas on images."""
    
    def __init__(self):
        self.left: Optional[int] = None
        self.top: Optional[int] = None
        self.right: Optional[int] = None
        self.bottom: Optional[int] = None
        self.is_active: bool = False
        self.shape: str = "rectangle"  # "rectangle" or "circle"
    
    def set_coordinates(self, left: int, top: int, right: int, bottom: int) -> None:
        """Set the selection coordinates."""
        self.left = left
        self.top = top
        self.right = right
        self.bottom = bottom
        self.is_active = True
    
    def clear(self) -> None:
        """Clear the selection."""
        self.left = None
        self.top = None
        self.right = None
        self.bottom = None
        self.is_active = False
        self.shape = self.shape  # keep last used shape

    def set_shape(self, shape: str) -> None:
        """Set the selection shape: 'rectangle' or 'circle'."""
        if shape in ("rectangle", "circle"):
            self.shape = shape
    
    def get_coordinates(self) -> Optional[Tuple[int, int, int, int]]:
        """Get the selection coordinates as a tuple."""
        if self.is_active and all(coord is not None for coord in [self.left, self.top, self.right, self.bottom]):
            return (self.left, self.top, self.right, self.bottom)
        return None
    
    def get_dict(self) -> Optional[Dict[str, int]]:
        """Get the selection coordinates as a dictionary."""
        coords = self.get_coordinates()
        if coords:
            return {
                "left": coords[0],
                "top": coords[1], 
                "right": coords[2],
                "bottom": coords[3]
            }
        return None
    
    def is_valid(self) -> bool:
        """Check if the selection is valid (has area > 0)."""
        coords = self.get_coordinates()
        if coords:
            left, top, right, bottom = coords
            return right > left and bottom > top
        return False
    
    def crop_image(self, image: Image.Image) -> Optional[Image.Image]:
        """Crop the given image to the selection area."""
        coords = self.get_coordinates()
        if coords and self.is_valid():
            # For both rectangle and circle, return the bounding box crop
            return image.crop(coords)
        return None
    
    def apply_to_image(self, image: Image.Image, processed_selection: Image.Image) -> Image.Image:
        """Apply the processed selection back to the original image."""
        coords = self.get_coordinates()
        if coords and self.is_valid():
            # Create a copy to avoid modifying the original
            result_image = image.copy()
            if self.shape == "circle":
                # Create circular mask for blending only inside the circle
                width = self.right - self.left
                height = self.bottom - self.top
                mask = Image.new("L", (width, height), 0)
                draw = ImageDraw.Draw(mask)
                draw.ellipse((0, 0, width, height), fill=255)
                result_image.paste(processed_selection, (self.left, self.top), mask)
            else:
                result_image.paste(processed_selection, (self.left, self.top))
            return result_image
        return image
