"""Output target schemas (CRUD, processing state, metrics)."""

from datetime import datetime
from typing import Dict, Optional, List

from pydantic import BaseModel, Field

DEFAULT_STATE_CHECK_INTERVAL = 30  # seconds between health checks


class KeyColorRectangleSchema(BaseModel):
    """A named rectangle for key color extraction (relative coords 0.0-1.0)."""

    name: str = Field(description="Rectangle name", min_length=1, max_length=50)
    x: float = Field(default=0.0, description="Left edge (0.0-1.0)", ge=0.0, le=1.0)
    y: float = Field(default=0.0, description="Top edge (0.0-1.0)", ge=0.0, le=1.0)
    width: float = Field(default=1.0, description="Width (0.0-1.0)", gt=0.0, le=1.0)
    height: float = Field(default=1.0, description="Height (0.0-1.0)", gt=0.0, le=1.0)


class KeyColorsSettingsSchema(BaseModel):
    """Settings for key colors extraction."""

    fps: int = Field(default=10, description="Extraction rate (1-60)", ge=1, le=60)
    interpolation_mode: str = Field(
        default="average", description="Color mode (average, median, dominant)"
    )
    smoothing: float = Field(
        default=0.3, description="Temporal smoothing (0.0-1.0)", ge=0.0, le=1.0
    )
    pattern_template_id: str = Field(
        default="", description="Pattern template ID for rectangle layout"
    )
    brightness: float = Field(
        default=1.0, description="Output brightness (0.0-1.0)", ge=0.0, le=1.0
    )
    brightness_value_source_id: str = Field(default="", description="Brightness value source ID")


class ExtractedColorResponse(BaseModel):
    """A single extracted color."""

    r: int = Field(description="Red (0-255)")
    g: int = Field(description="Green (0-255)")
    b: int = Field(description="Blue (0-255)")
    hex: str = Field(description="Hex color (#rrggbb)")


class KeyColorsResponse(BaseModel):
    """Extracted key colors for a target."""

    target_id: str = Field(description="Target ID")
    colors: Dict[str, ExtractedColorResponse] = Field(description="Rectangle name -> color")
    timestamp: Optional[datetime] = Field(None, description="Extraction timestamp")


class HALightMappingSchema(BaseModel):
    """Maps an LED range to one HA light entity."""

    entity_id: str = Field(description="HA light entity ID (e.g. 'light.living_room')")
    led_start: int = Field(default=0, ge=0, description="Start LED index (0-based)")
    led_end: int = Field(default=-1, description="End LED index (-1 = last)")
    brightness_scale: float = Field(
        default=1.0, ge=0.0, le=1.0, description="Brightness multiplier"
    )


class OutputTargetCreate(BaseModel):
    """Request to create an output target."""

    name: str = Field(description="Target name", min_length=1, max_length=100)
    target_type: str = Field(default="led", description="Target type (led, key_colors, ha_light)")
    # LED target fields
    device_id: str = Field(default="", description="LED device ID")
    color_strip_source_id: str = Field(default="", description="Color strip source ID")
    brightness_value_source_id: str = Field(default="", description="Brightness value source ID")
    fps: int = Field(default=30, ge=1, le=90, description="Target send FPS (1-90)")
    keepalive_interval: float = Field(
        default=1.0,
        description="Keepalive send interval when screen is static (0.5-5.0s)",
        ge=0.5,
        le=5.0,
    )
    state_check_interval: int = Field(
        default=DEFAULT_STATE_CHECK_INTERVAL,
        description="Device health check interval (5-600s)",
        ge=5,
        le=600,
    )
    min_brightness_threshold: int = Field(
        default=0,
        ge=0,
        le=254,
        description="Min brightness threshold (0=disabled); below this → off",
    )
    adaptive_fps: bool = Field(
        default=False, description="Auto-reduce FPS when device is unresponsive"
    )
    protocol: str = Field(
        default="ddp",
        pattern="^(ddp|http)$",
        description="Send protocol: ddp (UDP) or http (JSON API)",
    )
    # KC target fields
    picture_source_id: str = Field(
        default="", description="Picture source ID (for key_colors targets)"
    )
    key_colors_settings: Optional[KeyColorsSettingsSchema] = Field(
        None, description="Key colors settings (for key_colors targets)"
    )
    # HA light target fields
    ha_source_id: str = Field(
        default="", description="Home Assistant source ID (for ha_light targets)"
    )
    ha_light_mappings: Optional[List[HALightMappingSchema]] = Field(
        None, description="LED-to-light mappings (for ha_light targets)"
    )
    update_rate: float = Field(
        default=2.0, ge=0.5, le=5.0, description="Service call rate in Hz (for ha_light targets)"
    )
    transition: float = Field(
        default=0.5, ge=0.0, le=10.0, description="HA transition seconds (for ha_light targets)"
    )
    color_tolerance: int = Field(
        default=5,
        ge=0,
        le=50,
        description="Skip service call if RGB delta < this (for ha_light targets)",
    )
    description: Optional[str] = Field(None, description="Optional description", max_length=500)
    tags: List[str] = Field(default_factory=list, description="User-defined tags")


class OutputTargetUpdate(BaseModel):
    """Request to update an output target."""

    name: Optional[str] = Field(None, description="Target name", min_length=1, max_length=100)
    # LED target fields
    device_id: Optional[str] = Field(None, description="LED device ID")
    color_strip_source_id: Optional[str] = Field(None, description="Color strip source ID")
    brightness_value_source_id: Optional[str] = Field(
        None, description="Brightness value source ID"
    )
    fps: Optional[int] = Field(None, ge=1, le=90, description="Target send FPS (1-90)")
    keepalive_interval: Optional[float] = Field(
        None, description="Keepalive interval (0.5-5.0s)", ge=0.5, le=5.0
    )
    state_check_interval: Optional[int] = Field(
        None, description="Health check interval (5-600s)", ge=5, le=600
    )
    min_brightness_threshold: Optional[int] = Field(
        None, ge=0, le=254, description="Min brightness threshold (0=disabled); below this → off"
    )
    adaptive_fps: Optional[bool] = Field(
        None, description="Auto-reduce FPS when device is unresponsive"
    )
    protocol: Optional[str] = Field(
        None, pattern="^(ddp|http)$", description="Send protocol: ddp (UDP) or http (JSON API)"
    )
    # KC target fields
    picture_source_id: Optional[str] = Field(
        None, description="Picture source ID (for key_colors targets)"
    )
    key_colors_settings: Optional[KeyColorsSettingsSchema] = Field(
        None, description="Key colors settings (for key_colors targets)"
    )
    # HA light target fields
    ha_source_id: Optional[str] = Field(
        None, description="Home Assistant source ID (for ha_light targets)"
    )
    ha_light_mappings: Optional[List[HALightMappingSchema]] = Field(
        None, description="LED-to-light mappings (for ha_light targets)"
    )
    update_rate: Optional[float] = Field(
        None, ge=0.5, le=5.0, description="Service call rate Hz (for ha_light targets)"
    )
    transition: Optional[float] = Field(
        None, ge=0.0, le=10.0, description="HA transition seconds (for ha_light targets)"
    )
    color_tolerance: Optional[int] = Field(
        None, ge=0, le=50, description="RGB delta tolerance (for ha_light targets)"
    )
    description: Optional[str] = Field(None, description="Optional description", max_length=500)
    tags: Optional[List[str]] = None


class OutputTargetResponse(BaseModel):
    """Output target response."""

    id: str = Field(description="Target ID")
    name: str = Field(description="Target name")
    target_type: str = Field(description="Target type")
    # LED target fields
    device_id: str = Field(default="", description="LED device ID")
    color_strip_source_id: str = Field(default="", description="Color strip source ID")
    brightness_value_source_id: str = Field(default="", description="Brightness value source ID")
    fps: Optional[int] = Field(None, description="Target send FPS")
    keepalive_interval: float = Field(default=1.0, description="Keepalive interval (s)")
    state_check_interval: int = Field(
        default=DEFAULT_STATE_CHECK_INTERVAL, description="Health check interval (s)"
    )
    min_brightness_threshold: int = Field(
        default=0, description="Min brightness threshold (0=disabled)"
    )
    adaptive_fps: bool = Field(
        default=False, description="Auto-reduce FPS when device is unresponsive"
    )
    protocol: str = Field(default="ddp", description="Send protocol (ddp or http)")
    # KC target fields
    picture_source_id: str = Field(default="", description="Picture source ID (key_colors)")
    key_colors_settings: Optional[KeyColorsSettingsSchema] = Field(
        None, description="Key colors settings"
    )
    # HA light target fields
    ha_source_id: str = Field(default="", description="Home Assistant source ID (ha_light)")
    ha_light_mappings: Optional[List[HALightMappingSchema]] = Field(
        None, description="LED-to-light mappings (ha_light)"
    )
    update_rate: Optional[float] = Field(None, description="Service call rate Hz (ha_light)")
    ha_transition: Optional[float] = Field(None, description="HA transition seconds (ha_light)")
    color_tolerance: Optional[int] = Field(None, description="RGB delta tolerance (ha_light)")
    description: Optional[str] = Field(None, description="Description")
    tags: List[str] = Field(default_factory=list, description="User-defined tags")
    created_at: datetime = Field(description="Creation timestamp")
    updated_at: datetime = Field(description="Last update timestamp")


class OutputTargetListResponse(BaseModel):
    """List of output targets response."""

    targets: List[OutputTargetResponse] = Field(description="List of output targets")
    count: int = Field(description="Number of targets")


class TargetProcessingState(BaseModel):
    """Processing state for an output target."""

    target_id: str = Field(description="Target ID")
    device_id: Optional[str] = Field(None, description="Device ID")
    color_strip_source_id: str = Field(default="", description="Color strip source ID")
    processing: bool = Field(description="Whether processing is active")
    fps_actual: Optional[float] = Field(None, description="Actual FPS achieved")
    fps_potential: Optional[float] = Field(
        None, description="Potential FPS (processing speed without throttle)"
    )
    fps_target: Optional[int] = Field(None, description="Target FPS")
    frames_skipped: Optional[int] = Field(None, description="Frames skipped (no screen change)")
    frames_keepalive: Optional[int] = Field(
        None, description="Keepalive frames sent during standby"
    )
    fps_current: Optional[int] = Field(None, description="Frames sent in the last second")
    timing_send_ms: Optional[float] = Field(None, description="DDP send time (ms)")
    timing_extract_ms: Optional[float] = Field(
        None, description="Border pixel extraction time (ms)"
    )
    timing_map_leds_ms: Optional[float] = Field(None, description="LED color mapping time (ms)")
    timing_smooth_ms: Optional[float] = Field(None, description="Temporal smoothing time (ms)")
    timing_total_ms: Optional[float] = Field(
        None, description="Total processing time per frame (ms)"
    )
    timing_audio_read_ms: Optional[float] = Field(None, description="Audio device read time (ms)")
    timing_audio_fft_ms: Optional[float] = Field(None, description="Audio FFT analysis time (ms)")
    timing_audio_render_ms: Optional[float] = Field(
        None, description="Audio visualization render time (ms)"
    )
    timing_calc_colors_ms: Optional[float] = Field(
        None, description="Color calculation time (ms, KC targets)"
    )
    timing_broadcast_ms: Optional[float] = Field(
        None, description="WebSocket broadcast time (ms, KC targets)"
    )
    display_index: Optional[int] = Field(None, description="Current display index")
    overlay_active: bool = Field(
        default=False, description="Whether visualization overlay is active"
    )
    last_update: Optional[datetime] = Field(None, description="Last successful update")
    errors: List[str] = Field(default_factory=list, description="Recent errors")
    device_online: bool = Field(default=False, description="Whether device is reachable")
    device_latency_ms: Optional[float] = Field(None, description="Health check latency in ms")
    device_name: Optional[str] = Field(None, description="Device name reported by firmware")
    device_version: Optional[str] = Field(None, description="Firmware version")
    device_led_count: Optional[int] = Field(None, description="LED count reported by device")
    device_rgbw: Optional[bool] = Field(None, description="Whether device uses RGBW LEDs")
    device_led_type: Optional[str] = Field(
        None, description="LED chip type (e.g. WS2812B, SK6812 RGBW)"
    )
    device_fps: Optional[int] = Field(
        None, description="Device-reported FPS (WLED internal refresh rate)"
    )
    device_last_checked: Optional[datetime] = Field(None, description="Last health check time")
    device_error: Optional[str] = Field(None, description="Last health check error")
    device_streaming_reachable: Optional[bool] = Field(
        None, description="Device reachable during streaming (HTTP probe)"
    )
    fps_effective: Optional[int] = Field(None, description="Effective FPS after adaptive reduction")


class TargetMetricsResponse(BaseModel):
    """Target metrics response."""

    target_id: str = Field(description="Target ID")
    device_id: Optional[str] = Field(None, description="Device ID")
    processing: bool = Field(description="Whether processing is active")
    fps_actual: Optional[float] = Field(None, description="Actual FPS")
    fps_target: Optional[int] = Field(None, description="Target FPS")
    uptime_seconds: float = Field(description="Processing uptime in seconds")
    frames_processed: int = Field(description="Total frames processed")
    errors_count: int = Field(description="Total error count")
    last_error: Optional[str] = Field(None, description="Last error message")
    last_update: Optional[datetime] = Field(None, description="Last update timestamp")


class BulkTargetRequest(BaseModel):
    """Request body for bulk start/stop operations."""

    ids: List[str] = Field(description="List of target IDs to operate on")


class BulkTargetResponse(BaseModel):
    """Response for bulk start/stop operations."""

    started: List[str] = Field(
        default_factory=list, description="IDs that were successfully started"
    )
    stopped: List[str] = Field(
        default_factory=list, description="IDs that were successfully stopped"
    )
    errors: Dict[str, str] = Field(
        default_factory=dict, description="Map of target ID to error message for failures"
    )


class KCTestRectangleResponse(BaseModel):
    """A rectangle with its extracted color from a KC test."""

    name: str = Field(description="Rectangle name")
    x: float = Field(description="Left edge (0.0-1.0)")
    y: float = Field(description="Top edge (0.0-1.0)")
    width: float = Field(description="Width (0.0-1.0)")
    height: float = Field(description="Height (0.0-1.0)")
    color: ExtractedColorResponse = Field(description="Extracted color for this rectangle")


class KCTestResponse(BaseModel):
    """Response from testing a KC target."""

    image: str = Field(description="Base64 data URI of the captured frame")
    rectangles: List[KCTestRectangleResponse] = Field(
        description="Rectangles with extracted colors"
    )
    interpolation_mode: str = Field(description="Color extraction mode used")
    pattern_template_name: str = Field(description="Pattern template name")
