"""Value source schemas — discriminated unions per source type."""

from datetime import datetime
from typing import Annotated, List, Literal, Optional, Union

from pydantic import BaseModel, Discriminator, Field, Tag

# =====================================================================
# Response schemas (per-type, discriminated union)
# =====================================================================


class _ValueSourceResponseBase(BaseModel):
    """Shared fields for all value source responses."""

    id: str = Field(description="Source ID")
    name: str = Field(description="Source name")
    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 StaticValueSourceResponse(_ValueSourceResponseBase):
    source_type: Literal["static"] = "static"
    return_type: Literal["float"] = "float"
    value: float = Field(description="Constant value (0.0-1.0)")


class AnimatedValueSourceResponse(_ValueSourceResponseBase):
    source_type: Literal["animated"] = "animated"
    return_type: Literal["float"] = "float"
    waveform: str = Field(description="Waveform type")
    speed: float = Field(description="Cycles per minute")
    min_value: float = Field(description="Minimum output")
    max_value: float = Field(description="Maximum output")


class AudioValueSourceResponse(_ValueSourceResponseBase):
    source_type: Literal["audio"] = "audio"
    return_type: Literal["float"] = "float"
    audio_source_id: str = Field(description="Mono audio source ID")
    mode: str = Field(description="Audio mode: rms|peak|beat")
    sensitivity: float = Field(description="Gain multiplier")
    smoothing: float = Field(description="Temporal smoothing")
    min_value: float = Field(description="Minimum output")
    max_value: float = Field(description="Maximum output")
    auto_gain: bool = Field(description="Auto-normalize audio levels")


class AdaptiveTimeValueSourceResponse(_ValueSourceResponseBase):
    source_type: Literal["adaptive_time"] = "adaptive_time"
    return_type: Literal["float"] = "float"
    schedule: list = Field(description="Time-of-day schedule")
    min_value: float = Field(description="Minimum output")
    max_value: float = Field(description="Maximum output")


class AdaptiveSceneValueSourceResponse(_ValueSourceResponseBase):
    source_type: Literal["adaptive_scene"] = "adaptive_scene"
    return_type: Literal["float"] = "float"
    picture_source_id: str = Field(description="Picture source ID")
    scene_behavior: str = Field(description="Scene behavior: complement|match")
    sensitivity: float = Field(description="Gain multiplier")
    smoothing: float = Field(description="Temporal smoothing")
    min_value: float = Field(description="Minimum output")
    max_value: float = Field(description="Maximum output")


class DaylightValueSourceResponse(_ValueSourceResponseBase):
    source_type: Literal["daylight"] = "daylight"
    return_type: Literal["float"] = "float"
    speed: float = Field(description="Simulation speed multiplier")
    use_real_time: bool = Field(description="Use wall-clock time")
    latitude: float = Field(description="Geographic latitude")
    min_value: float = Field(description="Minimum output")
    max_value: float = Field(description="Maximum output")


class StaticColorValueSourceResponse(_ValueSourceResponseBase):
    source_type: Literal["static_color"] = "static_color"
    return_type: Literal["color"] = "color"
    color: List[int] = Field(description="Static RGB color [R,G,B]")


class AnimatedColorValueSourceResponse(_ValueSourceResponseBase):
    source_type: Literal["animated_color"] = "animated_color"
    return_type: Literal["color"] = "color"
    colors: List[List[int]] = Field(description="Color list [[R,G,B], ...]")
    speed: float = Field(description="Cycles per minute")
    easing: str = Field(description="Color easing: linear|step")


class AdaptiveTimeColorValueSourceResponse(_ValueSourceResponseBase):
    source_type: Literal["adaptive_time_color"] = "adaptive_time_color"
    return_type: Literal["color"] = "color"
    schedule: list = Field(description="Color schedule")


class HAEntityValueSourceResponse(_ValueSourceResponseBase):
    source_type: Literal["ha_entity"] = "ha_entity"
    return_type: Literal["float"] = "float"
    ha_source_id: str = Field(description="Home Assistant source ID")
    entity_id: str = Field(description="HA entity ID (e.g. sensor.temperature)")
    attribute: str = Field("", description="Optional attribute name (empty = use state)")
    min_ha_value: float = Field(description="Raw HA value mapped to output 0.0")
    max_ha_value: float = Field(description="Raw HA value mapped to output 1.0")
    smoothing: float = Field(description="EMA smoothing factor (0.0-1.0)")


class GradientMapValueSourceResponse(_ValueSourceResponseBase):
    source_type: Literal["gradient_map"] = "gradient_map"
    return_type: Literal["color"] = "color"
    value_source_id: str = Field(description="Input float value source ID")
    gradient_id: str = Field(description="Gradient entity ID")
    easing: str = Field(description="Interpolation mode: linear|step")


class CSSExtractValueSourceResponse(_ValueSourceResponseBase):
    source_type: Literal["css_extract"] = "css_extract"
    return_type: Literal["color"] = "color"
    color_strip_source_id: str = Field(description="Color strip source ID")
    led_start: int = Field(description="Start of LED range (0-based)")
    led_end: int = Field(description="End of LED range (-1 = whole strip)")


class SystemMetricsValueSourceResponse(_ValueSourceResponseBase):
    source_type: Literal["system_metrics"] = "system_metrics"
    return_type: Literal["float"] = "float"
    metric: str = Field(description="System metric to monitor")
    min_value: float = Field(description="Min value for range-based metrics")
    max_value: float = Field(description="Max value for range-based metrics")
    max_rate: float = Field(description="Max rate in bytes/sec for network metrics")
    disk_path: str = Field(description="Disk path for disk_usage metric")
    sensor_label: str = Field(description="Sensor label for cpu_temp/fan_speed")
    poll_interval: float = Field(description="Seconds between reads")
    smoothing: float = Field(description="EMA smoothing factor (0.0-1.0)")


ValueSourceResponse = Annotated[
    Union[
        Annotated[StaticValueSourceResponse, Tag("static")],
        Annotated[AnimatedValueSourceResponse, Tag("animated")],
        Annotated[AudioValueSourceResponse, Tag("audio")],
        Annotated[AdaptiveTimeValueSourceResponse, Tag("adaptive_time")],
        Annotated[AdaptiveSceneValueSourceResponse, Tag("adaptive_scene")],
        Annotated[DaylightValueSourceResponse, Tag("daylight")],
        Annotated[StaticColorValueSourceResponse, Tag("static_color")],
        Annotated[AnimatedColorValueSourceResponse, Tag("animated_color")],
        Annotated[AdaptiveTimeColorValueSourceResponse, Tag("adaptive_time_color")],
        Annotated[HAEntityValueSourceResponse, Tag("ha_entity")],
        Annotated[GradientMapValueSourceResponse, Tag("gradient_map")],
        Annotated[CSSExtractValueSourceResponse, Tag("css_extract")],
        Annotated[SystemMetricsValueSourceResponse, Tag("system_metrics")],
    ],
    Discriminator("source_type"),
]

# =====================================================================
# Create schemas (per-type, discriminated union)
# =====================================================================


class _ValueSourceCreateBase(BaseModel):
    """Shared fields for all value source create requests."""

    name: str = Field(description="Source name", min_length=1, max_length=100)
    description: Optional[str] = Field(None, description="Optional description", max_length=500)
    tags: List[str] = Field(default_factory=list, description="User-defined tags")


class StaticValueSourceCreate(_ValueSourceCreateBase):
    source_type: Literal["static"] = "static"
    value: float = Field(1.0, description="Constant value (0.0-1.0)", ge=0.0, le=1.0)


class AnimatedValueSourceCreate(_ValueSourceCreateBase):
    source_type: Literal["animated"] = "animated"
    waveform: str = Field("sine", description="Waveform: sine|triangle|square|sawtooth")
    speed: float = Field(10.0, description="Cycles per minute", ge=0.1, le=120.0)
    min_value: float = Field(0.0, description="Minimum output (0.0-1.0)", ge=0.0, le=1.0)
    max_value: float = Field(1.0, description="Maximum output (0.0-1.0)", ge=0.0, le=1.0)


class AudioValueSourceCreate(_ValueSourceCreateBase):
    source_type: Literal["audio"] = "audio"
    audio_source_id: str = Field("", description="Mono audio source ID")
    mode: str = Field("rms", description="Audio mode: rms|peak|beat")
    sensitivity: float = Field(1.0, description="Gain multiplier (0.1-20.0)", ge=0.1, le=20.0)
    smoothing: float = Field(0.3, description="Temporal smoothing (0.0-1.0)", ge=0.0, le=1.0)
    min_value: float = Field(0.0, description="Minimum output (0.0-1.0)", ge=0.0, le=1.0)
    max_value: float = Field(1.0, description="Maximum output (0.0-1.0)", ge=0.0, le=1.0)
    auto_gain: bool = Field(False, description="Auto-normalize audio levels to full range")


class AdaptiveTimeValueSourceCreate(_ValueSourceCreateBase):
    source_type: Literal["adaptive_time"] = "adaptive_time"
    schedule: list = Field(description="Schedule: [{time: 'HH:MM', value: 0.0-1.0}]")
    min_value: float = Field(0.0, description="Minimum output (0.0-1.0)", ge=0.0, le=1.0)
    max_value: float = Field(1.0, description="Maximum output (0.0-1.0)", ge=0.0, le=1.0)


class AdaptiveSceneValueSourceCreate(_ValueSourceCreateBase):
    source_type: Literal["adaptive_scene"] = "adaptive_scene"
    picture_source_id: str = Field("", description="Picture source ID for scene mode")
    scene_behavior: str = Field("complement", description="Scene behavior: complement|match")
    sensitivity: float = Field(1.0, description="Gain multiplier (0.1-20.0)", ge=0.1, le=20.0)
    smoothing: float = Field(0.3, description="Temporal smoothing (0.0-1.0)", ge=0.0, le=1.0)
    min_value: float = Field(0.0, description="Minimum output (0.0-1.0)", ge=0.0, le=1.0)
    max_value: float = Field(1.0, description="Maximum output (0.0-1.0)", ge=0.0, le=1.0)


class DaylightValueSourceCreate(_ValueSourceCreateBase):
    source_type: Literal["daylight"] = "daylight"
    speed: float = Field(1.0, description="Simulation speed multiplier", ge=0.1, le=120.0)
    use_real_time: bool = Field(False, description="Use wall-clock time instead of simulation")
    latitude: float = Field(50.0, description="Geographic latitude (-90 to 90)", ge=-90.0, le=90.0)
    min_value: float = Field(0.0, description="Minimum output (0.0-1.0)", ge=0.0, le=1.0)
    max_value: float = Field(1.0, description="Maximum output (0.0-1.0)", ge=0.0, le=1.0)


class StaticColorValueSourceCreate(_ValueSourceCreateBase):
    source_type: Literal["static_color"] = "static_color"
    color: List[int] = Field(
        default_factory=lambda: [255, 255, 255],
        description="Static RGB color [R,G,B]",
    )


class AnimatedColorValueSourceCreate(_ValueSourceCreateBase):
    source_type: Literal["animated_color"] = "animated_color"
    colors: List[List[int]] = Field(
        default_factory=lambda: [[255, 0, 0], [0, 255, 0], [0, 0, 255]],
        description="Color list [[R,G,B], ...]",
    )
    speed: float = Field(10.0, description="Cycles per minute", ge=0.1, le=120.0)
    easing: str = Field("linear", description="Color easing: linear|step")


class AdaptiveTimeColorValueSourceCreate(_ValueSourceCreateBase):
    source_type: Literal["adaptive_time_color"] = "adaptive_time_color"
    schedule: list = Field(description="Schedule: [{time: 'HH:MM', color: [R,G,B]}]")


class HAEntityValueSourceCreate(_ValueSourceCreateBase):
    source_type: Literal["ha_entity"] = "ha_entity"
    ha_source_id: str = Field(description="Home Assistant source ID")
    entity_id: str = Field(description="HA entity ID")
    attribute: str = Field("", description="Optional attribute name")
    min_ha_value: float = Field(0.0, description="Raw HA value mapped to output 0.0")
    max_ha_value: float = Field(100.0, description="Raw HA value mapped to output 1.0")
    smoothing: float = Field(0.0, description="EMA smoothing (0.0-1.0)", ge=0.0, le=1.0)


class GradientMapValueSourceCreate(_ValueSourceCreateBase):
    source_type: Literal["gradient_map"] = "gradient_map"
    value_source_id: str = Field(description="Input float value source ID")
    gradient_id: str = Field("", description="Gradient entity ID")
    easing: str = Field("linear", description="Interpolation: linear|step")


class CSSExtractValueSourceCreate(_ValueSourceCreateBase):
    source_type: Literal["css_extract"] = "css_extract"
    color_strip_source_id: str = Field(description="Color strip source ID")
    led_start: int = Field(0, description="Start of LED range (0-based)", ge=0)
    led_end: int = Field(-1, description="End of LED range (-1 = whole strip)")


class SystemMetricsValueSourceCreate(_ValueSourceCreateBase):
    source_type: Literal["system_metrics"] = "system_metrics"
    metric: str = Field("cpu_load", description="System metric to monitor")
    min_value: float = Field(0.0, description="Min value for normalization")
    max_value: float = Field(100.0, description="Max value for normalization")
    max_rate: float = Field(125_000_000.0, description="Max rate bytes/sec for network")
    disk_path: str = Field("", description="Disk path for disk_usage")
    sensor_label: str = Field("", description="Sensor label for cpu_temp/fan_speed")
    poll_interval: float = Field(1.0, description="Poll interval in seconds", ge=0.1, le=60.0)
    smoothing: float = Field(0.0, description="EMA smoothing (0.0-1.0)", ge=0.0, le=1.0)


ValueSourceCreate = Annotated[
    Union[
        Annotated[StaticValueSourceCreate, Tag("static")],
        Annotated[AnimatedValueSourceCreate, Tag("animated")],
        Annotated[AudioValueSourceCreate, Tag("audio")],
        Annotated[AdaptiveTimeValueSourceCreate, Tag("adaptive_time")],
        Annotated[AdaptiveSceneValueSourceCreate, Tag("adaptive_scene")],
        Annotated[DaylightValueSourceCreate, Tag("daylight")],
        Annotated[StaticColorValueSourceCreate, Tag("static_color")],
        Annotated[AnimatedColorValueSourceCreate, Tag("animated_color")],
        Annotated[AdaptiveTimeColorValueSourceCreate, Tag("adaptive_time_color")],
        Annotated[HAEntityValueSourceCreate, Tag("ha_entity")],
        Annotated[GradientMapValueSourceCreate, Tag("gradient_map")],
        Annotated[CSSExtractValueSourceCreate, Tag("css_extract")],
        Annotated[SystemMetricsValueSourceCreate, Tag("system_metrics")],
    ],
    Discriminator("source_type"),
]

# =====================================================================
# Update schemas (per-type, discriminated union)
# =====================================================================


class _ValueSourceUpdateBase(BaseModel):
    """Shared fields for all value source update requests."""

    name: Optional[str] = Field(None, description="Source name", min_length=1, max_length=100)
    description: Optional[str] = Field(None, description="Optional description", max_length=500)
    tags: Optional[List[str]] = None


class StaticValueSourceUpdate(_ValueSourceUpdateBase):
    source_type: Literal["static"] = "static"
    value: Optional[float] = Field(None, description="Constant value (0.0-1.0)", ge=0.0, le=1.0)


class AnimatedValueSourceUpdate(_ValueSourceUpdateBase):
    source_type: Literal["animated"] = "animated"
    waveform: Optional[str] = Field(None, description="Waveform: sine|triangle|square|sawtooth")
    speed: Optional[float] = Field(None, description="Cycles per minute", ge=0.1, le=120.0)
    min_value: Optional[float] = Field(None, description="Minimum output", ge=0.0, le=1.0)
    max_value: Optional[float] = Field(None, description="Maximum output", ge=0.0, le=1.0)


class AudioValueSourceUpdate(_ValueSourceUpdateBase):
    source_type: Literal["audio"] = "audio"
    audio_source_id: Optional[str] = Field(None, description="Mono audio source ID")
    mode: Optional[str] = Field(None, description="Audio mode: rms|peak|beat")
    sensitivity: Optional[float] = Field(None, description="Gain multiplier", ge=0.1, le=20.0)
    smoothing: Optional[float] = Field(None, description="Temporal smoothing", ge=0.0, le=1.0)
    min_value: Optional[float] = Field(None, description="Minimum output", ge=0.0, le=1.0)
    max_value: Optional[float] = Field(None, description="Maximum output", ge=0.0, le=1.0)
    auto_gain: Optional[bool] = Field(None, description="Auto-normalize audio levels")


class AdaptiveTimeValueSourceUpdate(_ValueSourceUpdateBase):
    source_type: Literal["adaptive_time"] = "adaptive_time"
    schedule: Optional[list] = Field(None, description="Time-of-day schedule")
    min_value: Optional[float] = Field(None, description="Minimum output", ge=0.0, le=1.0)
    max_value: Optional[float] = Field(None, description="Maximum output", ge=0.0, le=1.0)


class AdaptiveSceneValueSourceUpdate(_ValueSourceUpdateBase):
    source_type: Literal["adaptive_scene"] = "adaptive_scene"
    picture_source_id: Optional[str] = Field(None, description="Picture source ID")
    scene_behavior: Optional[str] = Field(None, description="Scene behavior")
    sensitivity: Optional[float] = Field(None, description="Gain multiplier", ge=0.1, le=20.0)
    smoothing: Optional[float] = Field(None, description="Temporal smoothing", ge=0.0, le=1.0)
    min_value: Optional[float] = Field(None, description="Minimum output", ge=0.0, le=1.0)
    max_value: Optional[float] = Field(None, description="Maximum output", ge=0.0, le=1.0)


class DaylightValueSourceUpdate(_ValueSourceUpdateBase):
    source_type: Literal["daylight"] = "daylight"
    speed: Optional[float] = Field(None, description="Simulation speed", ge=0.1, le=120.0)
    use_real_time: Optional[bool] = Field(None, description="Use wall-clock time")
    latitude: Optional[float] = Field(None, description="Geographic latitude", ge=-90.0, le=90.0)
    min_value: Optional[float] = Field(None, description="Minimum output", ge=0.0, le=1.0)
    max_value: Optional[float] = Field(None, description="Maximum output", ge=0.0, le=1.0)


class StaticColorValueSourceUpdate(_ValueSourceUpdateBase):
    source_type: Literal["static_color"] = "static_color"
    color: Optional[List[int]] = Field(None, description="Static RGB color [R,G,B]")


class AnimatedColorValueSourceUpdate(_ValueSourceUpdateBase):
    source_type: Literal["animated_color"] = "animated_color"
    colors: Optional[List[List[int]]] = Field(None, description="Color list [[R,G,B], ...]")
    speed: Optional[float] = Field(None, description="Cycles per minute", ge=0.1, le=120.0)
    easing: Optional[str] = Field(None, description="Color easing: linear|step")


class AdaptiveTimeColorValueSourceUpdate(_ValueSourceUpdateBase):
    source_type: Literal["adaptive_time_color"] = "adaptive_time_color"
    schedule: Optional[list] = Field(None, description="Color schedule")


class HAEntityValueSourceUpdate(_ValueSourceUpdateBase):
    source_type: Literal["ha_entity"] = "ha_entity"
    ha_source_id: Optional[str] = Field(None, description="Home Assistant source ID")
    entity_id: Optional[str] = Field(None, description="HA entity ID")
    attribute: Optional[str] = Field(None, description="Attribute name")
    min_ha_value: Optional[float] = Field(None, description="Min HA value")
    max_ha_value: Optional[float] = Field(None, description="Max HA value")
    smoothing: Optional[float] = Field(None, description="EMA smoothing", ge=0.0, le=1.0)


class GradientMapValueSourceUpdate(_ValueSourceUpdateBase):
    source_type: Literal["gradient_map"] = "gradient_map"
    value_source_id: Optional[str] = Field(None, description="Input value source ID")
    gradient_id: Optional[str] = Field(None, description="Gradient entity ID")
    easing: Optional[str] = Field(None, description="Interpolation mode")


class CSSExtractValueSourceUpdate(_ValueSourceUpdateBase):
    source_type: Literal["css_extract"] = "css_extract"
    color_strip_source_id: Optional[str] = Field(None, description="Color strip source ID")
    led_start: Optional[int] = Field(None, description="LED range start", ge=0)
    led_end: Optional[int] = Field(None, description="LED range end")


class SystemMetricsValueSourceUpdate(_ValueSourceUpdateBase):
    source_type: Literal["system_metrics"] = "system_metrics"
    metric: Optional[str] = Field(None, description="System metric")
    min_value: Optional[float] = Field(None, description="Min value")
    max_value: Optional[float] = Field(None, description="Max value")
    max_rate: Optional[float] = Field(None, description="Max rate bytes/sec")
    disk_path: Optional[str] = Field(None, description="Disk path")
    sensor_label: Optional[str] = Field(None, description="Sensor label")
    poll_interval: Optional[float] = Field(None, description="Poll interval", ge=0.1, le=60.0)
    smoothing: Optional[float] = Field(None, description="EMA smoothing", ge=0.0, le=1.0)


ValueSourceUpdate = Annotated[
    Union[
        Annotated[StaticValueSourceUpdate, Tag("static")],
        Annotated[AnimatedValueSourceUpdate, Tag("animated")],
        Annotated[AudioValueSourceUpdate, Tag("audio")],
        Annotated[AdaptiveTimeValueSourceUpdate, Tag("adaptive_time")],
        Annotated[AdaptiveSceneValueSourceUpdate, Tag("adaptive_scene")],
        Annotated[DaylightValueSourceUpdate, Tag("daylight")],
        Annotated[StaticColorValueSourceUpdate, Tag("static_color")],
        Annotated[AnimatedColorValueSourceUpdate, Tag("animated_color")],
        Annotated[AdaptiveTimeColorValueSourceUpdate, Tag("adaptive_time_color")],
        Annotated[HAEntityValueSourceUpdate, Tag("ha_entity")],
        Annotated[GradientMapValueSourceUpdate, Tag("gradient_map")],
        Annotated[CSSExtractValueSourceUpdate, Tag("css_extract")],
        Annotated[SystemMetricsValueSourceUpdate, Tag("system_metrics")],
    ],
    Discriminator("source_type"),
]

# =====================================================================
# List response
# =====================================================================


class ValueSourceListResponse(BaseModel):
    """List of value sources."""

    sources: List[ValueSourceResponse] = Field(description="List of value sources")
    count: int = Field(description="Number of sources")
