
import os
import cv2
import numpy as np
from PIL import Image, ImageEnhance
import pillow_heif

# Register HEIF opener
pillow_heif.register_heif_opener()

class ImageProcessor:
    def __init__(self):
        # Load face detector (Using face_recognition library as requested, 
        # but wrapping in try-except for environments where dlib is hard to install)
        try:
            import face_recognition
            self.face_recognition = face_recognition
            self.use_face_recognition_lib = True
        except ImportError:
            print("Warning: 'face_recognition' library not found. Falling back to OpenCV Haar Cascade.")
            self.use_face_recognition_lib = False
            self.face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

    def load_image(self, file_path: str) -> Image.Image:
        """Loads an image, converting HEIC to RGB if necessary."""
        try:
            # Pillow with pillow-heif can handle HEIC automatically if registered
            img = Image.open(file_path)
            # Ensure RGB for consistency (handle RGBA, P, etc.)
            if img.mode != 'RGB':
                img = img.convert('RGB')
            return img
        except Exception as e:
            raise ValueError(f"Failed to load image: {e}")

    def convert_heic_to_jpg(self, input_path: str, output_path: str, quality: int = 95):
        """Converts HEIC to JPG."""
        try:
            img = self.load_image(input_path)
            img.save(output_path, "JPEG", quality=quality)
            return output_path
        except Exception as e:
            print(f"Error converting HEIC: {e}")
            return None

    def auto_enhance(self, img: Image.Image, brightness_factor: float = 1.05, sharpness_factor: float = 1.15) -> Image.Image:
        """
        Applies subtle auto-enhancement logic.
        Default: slightly brighter and sharper.
        """
        # Adjust Brightness
        enhancer_b = ImageEnhance.Brightness(img)
        img = enhancer_b.enhance(brightness_factor)

        # Adjust Sharpness
        enhancer_s = ImageEnhance.Sharpness(img)
        img = enhancer_s.enhance(sharpness_factor)
        
        return img

    def get_smart_crop_box(self, img: Image.Image, target_ratio: float) -> tuple:
        """
        Calculates the crop box (left, top, right, bottom) focusing on faces.
        target_ratio: width / height (e.g., 4/6 = 0.666...)
        """
        cv_img = np.array(img)
        # RGB to BGR for OpenCV
        cv_img = cv_img[:, :, ::-1].copy()
        
        height, width = cv_img.shape[:2]
        img_ratio = width / height

        # Find faces
        faces = []
        if self.use_face_recognition_lib:
            # face_recognition uses RGB, so we can use the numpy array of PIL image directly (if we didn't swap BGR)
            # But here let's use the efficient method
            rgb_img = np.array(img)
            face_locations = self.face_recognition.face_locations(rgb_img)
            # Convert to (x, y, w, h) format for consistency: top, right, bottom, left
            faces = [(left, top, right - left, bottom - top) for top, right, bottom, left in face_locations]
        else:
            gray = cv2.cvtColor(cv_img, cv2.COLOR_BGR2GRAY)
            faces = self.face_cascade.detectMultiScale(gray, 1.1, 4)

        # Calculate center of interest (COI)
        if len(faces) > 0:
            # Calculate centroid of all faces
            center_x = sum([x + w/2 for x, y, w, h in faces]) / len(faces)
            center_y = sum([y + h/2 for x, y, w, h in faces]) / len(faces)
        else:
            # Default to image center
            center_x = width / 2
            center_y = height / 2

        # Determine dimensions of new crop
        if img_ratio > target_ratio:
            # Image is wider than target: fit height
            new_height = height
            new_width = int(height * target_ratio)
        else:
            # Image is taller than target: fit width
            new_width = width
            new_height = int(width / target_ratio)

        # Calculate top-left based on COI
        left = center_x - (new_width / 2)
        top = center_y - (new_height / 2)

        # Boundary checks
        if left < 0: left = 0
        if top < 0: top = 0
        if left + new_width > width: left = width - new_width
        if top + new_height > height: top = height - new_height

        return (int(left), int(top), int(left + new_width), int(top + new_height))

    def process_photo_for_print(self, input_path: str, output_path: str, target_ratio: float, 
                              do_enhance: bool = True, add_date: bool = False, date_text: str = None):
        """
        Main pipeline function.
        """
        img = self.load_image(input_path)

        # 1. Smart Crop
        crop_box = self.get_smart_crop_box(img, target_ratio)
        img = img.crop(crop_box)

        # 2. Auto Enhance
        if do_enhance:
            img = self.auto_enhance(img)

        # 3. Date Print (Simple Text Overlay)
        if add_date and date_text:
            # TODO: Implement text drawing with PIL.ImageDraw and ImageFont
            # This requires a font file (.ttf)
            pass

        img.save(output_path, quality=95)
        return output_path

# Example Usage
if __name__ == "__main__":
    # Create a dummy image for testing if none exists
    processor = ImageProcessor()
    print("Image Processor Initialized.")
    # processor.process_photo_for_print("test.heic", "output.jpg", 4/6)
