"""Pixel processing utilities for color correction and manipulation."""

from typing import List, Tuple, Union
import numpy as np

from wled_controller.utils import get_logger

logger = get_logger(__name__)

ColorList = Union[List[Tuple[int, int, int]], np.ndarray]


def _as_array(colors: ColorList) -> np.ndarray:
    """Convert list-of-tuples to (N,3) uint8 array, or pass through if already ndarray."""
    if isinstance(colors, np.ndarray):
        return colors
    return np.array(colors, dtype=np.uint8)


def smooth_colors(
    current_colors: ColorList,
    previous_colors: ColorList,
    smoothing_factor: float = 0.5,
) -> np.ndarray:
    """Smooth color transitions between frames.

    Args:
        current_colors: Current frame colors
        previous_colors: Previous frame colors
        smoothing_factor: Smoothing amount (0.0-1.0, where 0=no smoothing, 1=full smoothing)

    Returns:
        Smoothed colors as (N,3) uint8 ndarray
    """
    if not len(current_colors) or not len(previous_colors):
        return _as_array(current_colors)

    if len(current_colors) != len(previous_colors):
        logger.warning(
            f"Color count mismatch: current={len(current_colors)}, "
            f"previous={len(previous_colors)}. Skipping smoothing."
        )
        return _as_array(current_colors)

    if smoothing_factor <= 0:
        return _as_array(current_colors)
    if smoothing_factor >= 1:
        return _as_array(previous_colors)

    current = np.asarray(current_colors, dtype=np.float32)
    previous = np.asarray(previous_colors, dtype=np.float32)
    smoothed = current * (1 - smoothing_factor) + previous * smoothing_factor
    return np.clip(smoothed, 0, 255).astype(np.uint8)


def adjust_brightness_global(
    colors: ColorList,
    target_brightness: int,
) -> np.ndarray:
    """Adjust colors to achieve target global brightness.

    Args:
        colors: List of (R, G, B) tuples or (N,3) ndarray
        target_brightness: Target brightness (0-255)

    Returns:
        Adjusted colors as (N,3) uint8 ndarray
    """
    arr = _as_array(colors)
    if not len(arr) or target_brightness == 255:
        return arr

    scale = target_brightness / 255.0
    return (arr.astype(np.float32) * scale).astype(np.uint8)


def limit_brightness(
    colors: ColorList,
    max_brightness: int = 255,
) -> np.ndarray:
    """Limit maximum brightness of any color channel.

    Args:
        colors: List of (R, G, B) tuples or (N,3) ndarray
        max_brightness: Maximum allowed brightness (0-255)

    Returns:
        Limited colors as (N,3) uint8 ndarray
    """
    arr = _as_array(colors)
    if not len(arr) or max_brightness == 255:
        return arr

    arr_f = arr.astype(np.float32)
    max_vals = np.max(arr_f, axis=1)
    need_scale = max_vals > max_brightness
    if need_scale.any():
        scales = np.where(need_scale, max_brightness / np.maximum(max_vals, 1.0), 1.0)
        arr_f *= scales[:, np.newaxis]
    return arr_f.astype(np.uint8)
