import cv2
import numpy as np
from PIL import Image


def pil_to_cv2(pil_image: Image.Image) -> np.ndarray:
    """Convert PIL Image to OpenCV image (always BGR 3-channel when color)."""
    mode = pil_image.mode
    arr = np.array(pil_image)

    # Handle grayscale
    if mode in ("1", "L"):
        # arr is 2D. Convert to 3-channel BGR for downstream ops expecting color
        return cv2.cvtColor(arr, cv2.COLOR_GRAY2BGR)

    # Handle images with alpha channel by dropping alpha for processing
    if mode in ("LA", "RGBA"):
        # Convert to RGB first
        pil_rgb = pil_image.convert("RGB")
        arr = np.array(pil_rgb)
        return cv2.cvtColor(arr, cv2.COLOR_RGB2BGR)

    # Assume RGB-like
    if arr.ndim == 3 and arr.shape[2] == 3:
        return cv2.cvtColor(arr, cv2.COLOR_RGB2BGR)

    # Fallback: if still single-channel, expand to BGR
    if arr.ndim == 2:
        return cv2.cvtColor(arr, cv2.COLOR_GRAY2BGR)

    return arr


def cv2_to_pil(cv_image: np.ndarray) -> Image.Image:
    """Convert OpenCV image (BGR or GRAY) to PIL Image (RGB or L)."""
    if cv_image.ndim == 2:
        return Image.fromarray(cv_image)
    rgb = cv2.cvtColor(cv_image, cv2.COLOR_BGR2RGB)
    return Image.fromarray(rgb)


def clamp_int(value: float, min_value: int = 0, max_value: int = 255) -> int:
    return int(max(min_value, min(max_value, round(value))))

