/**
 * Shared TypeScript interfaces matching the backend Pydantic API schemas.
 *
 * These mirror the JSON shapes returned by the REST API. Field names use
 * snake_case to match the JSON payloads — no camelCase transformation is done.
 */

// ── Bindable Float ───────────────────────────────────────────
// A scalar that is either a static value (plain number) or bound to a value source (dict).

export type BindableFloat = number | { value: number; source_id: string };

/** Extract the static value from a BindableFloat. */
export function bindableValue(b: BindableFloat | undefined, fallback: number): number {
    if (b === undefined || b === null) return fallback;
    if (typeof b === 'number') return b;
    return b.value ?? fallback;
}

/** Extract the source_id from a BindableFloat (empty string = not bound). */
export function bindableSourceId(b: BindableFloat | undefined): string {
    if (b === undefined || b === null) return '';
    if (typeof b === 'number') return '';
    return b.source_id ?? '';
}

// ── Bindable Color ──────────────────────────────────────────
// An RGB color that is either static ([R,G,B] array) or bound to a color value source.

export type BindableColor = number[] | { color: number[]; source_id: string };

/** Extract the static [R,G,B] from a BindableColor. */
export function bindableColor(b: BindableColor | undefined, fallback: number[]): number[] {
    if (b === undefined || b === null) return fallback;
    if (Array.isArray(b)) return b;
    return b.color ?? fallback;
}

/** Extract the source_id from a BindableColor (empty string = not bound). */
export function bindableColorSourceId(b: BindableColor | undefined): string {
    if (b === undefined || b === null) return '';
    if (Array.isArray(b)) return '';
    return b.source_id ?? '';
}

// ── Device ────────────────────────────────────────────────────

export type DeviceType =
    | 'wled' | 'adalight' | 'ambiled' | 'mock' | 'mqtt' | 'ws'
    | 'openrgb' | 'dmx' | 'espnow' | 'hue' | 'usbhid' | 'spi'
    | 'chroma' | 'gamesense';

export interface Device {
    id: string;
    name: string;
    url: string;
    device_type: DeviceType;
    led_count: number;
    enabled: boolean;
    baud_rate?: number;
    auto_shutdown: boolean;
    send_latency_ms: number;
    rgbw: boolean;
    zone_mode: string;
    capabilities: string[];
    tags: string[];
    dmx_protocol: string;
    dmx_start_universe: number;
    dmx_start_channel: number;
    espnow_peer_mac: string;
    espnow_channel: number;
    hue_username: string;
    hue_client_key: string;
    hue_entertainment_group_id: string;
    spi_speed_hz: number;
    spi_led_type: string;
    chroma_device_type: string;
    gamesense_device_type: string;
    default_css_processing_template_id: string;
    created_at: string;
    updated_at: string;
}

// ── Output Target ─────────────────────────────────────────────

export type TargetType = 'led' | 'ha_light';

export interface HALightMapping {
    entity_id: string;
    led_start: number;
    led_end: number;
    brightness_scale: BindableFloat;
}

interface OutputTargetBase {
    id: string;
    name: string;
    target_type: TargetType;
    description?: string;
    tags: string[];
    created_at: string;
    updated_at: string;
}

export interface LedOutputTarget extends OutputTargetBase {
    target_type: 'led';
    device_id: string;
    color_strip_source_id: string;
    brightness?: BindableFloat;
    fps?: BindableFloat;
    keepalive_interval: number;
    state_check_interval: number;
    min_brightness_threshold?: BindableFloat;
    adaptive_fps: boolean;
    protocol: string;
}

export interface HALightOutputTarget extends OutputTargetBase {
    target_type: 'ha_light';
    ha_source_id: string;
    color_strip_source_id: string;
    brightness?: BindableFloat;
    ha_light_mappings?: HALightMapping[];
    update_rate?: BindableFloat;
    transition?: BindableFloat;
    color_tolerance?: BindableFloat;
    min_brightness_threshold?: BindableFloat;
}

export type OutputTarget = LedOutputTarget | HALightOutputTarget;

// ── Color Strip Source ────────────────────────────────────────

export type CSSSourceType =
    | 'picture' | 'picture_advanced' | 'static' | 'gradient'
    | 'color_cycle' | 'effect' | 'composite' | 'mapped'
    | 'audio' | 'api_input' | 'notification' | 'daylight'
    | 'candlelight' | 'processed' | 'weather' | 'key_colors'
    | 'game_event';

export interface ColorStop {
    position: number;
    color: number[];
    color_right?: number[];
}

export interface CompositeLayer {
    source_id: string;
    blend_mode: string;
    opacity: number;
    enabled: boolean;
    brightness_source_id?: string;
    processing_template_id?: string;
}

export interface MappedZone {
    source_id: string;
    start: number;
    end: number;
    reverse: boolean;
}

export interface AnimationConfig {
    enabled: boolean;
    type: string;
    speed: number;
}

export interface CalibrationLine {
    picture_source_id: string;
    edge: 'top' | 'right' | 'bottom' | 'left';
    led_count: number;
    span_start: number;
    span_end: number;
    reverse: boolean;
    border_width: number;
}

export interface Calibration {
    mode: 'simple' | 'advanced';
    lines?: CalibrationLine[];
    layout?: 'clockwise' | 'counterclockwise';
    start_position?: 'top_left' | 'top_right' | 'bottom_left' | 'bottom_right';
    offset?: number;
    leds_top?: number;
    leds_right?: number;
    leds_bottom?: number;
    leds_left?: number;
    span_top_start?: number;
    span_top_end?: number;
    span_right_start?: number;
    span_right_end?: number;
    span_bottom_start?: number;
    span_bottom_end?: number;
    span_left_start?: number;
    span_left_end?: number;
    skip_leds_start?: number;
    skip_leds_end?: number;
    border_width?: number;
}

export interface ColorStripSource {
    id: string;
    name: string;
    source_type: CSSSourceType;
    led_count: number;
    description?: string;
    tags: string[];
    overlay_active: boolean;
    clock_id?: string;
    created_at: string;
    updated_at: string;

    // Picture
    picture_source_id?: string;
    smoothing?: BindableFloat;
    interpolation_mode?: string;
    calibration?: Calibration;

    // Static / Effect / Candlelight
    color?: BindableColor;

    // Gradient
    stops?: ColorStop[];

    // Color cycle
    colors?: number[][];

    // Effect
    effect_type?: string;
    palette?: string;
    intensity?: BindableFloat;
    scale?: BindableFloat;
    mirror?: boolean;

    // Composite
    layers?: CompositeLayer[];

    // Mapped
    zones?: MappedZone[];

    // Audio
    visualization_mode?: string;
    audio_source_id?: string;
    sensitivity?: BindableFloat;
    color_peak?: BindableColor;

    // Animation
    animation?: AnimationConfig;
    speed?: BindableFloat;

    // API Input
    fallback_color?: BindableColor;
    timeout?: BindableFloat;
    interpolation?: string;

    // Notification
    notification_effect?: string;
    duration_ms?: number;
    default_color?: BindableColor | string;
    app_colors?: Record<string, string>;
    app_filter_mode?: string;
    app_filter_list?: string[];
    os_listener?: boolean;
    sound_volume?: BindableFloat;

    // Daylight
    use_real_time?: boolean;
    latitude?: number;

    // Candlelight
    num_candles?: number;
    wind_strength?: BindableFloat;

    // Processed
    input_source_id?: string;
    processing_template_id?: string;

    // Weather
    weather_source_id?: string;
    temperature_influence?: BindableFloat;

    // Key Colors
    rectangles?: KeyColorRectangle[];
    brightness?: BindableFloat;

    // Game Event
    game_integration_id?: string;
    idle_color?: BindableColor;
    event_mappings?: GameEventMapping[];
}

// ── Pattern Template ──────────────────────────────────────────

export interface KeyColorRectangle {
    name: string;
    x: number;
    y: number;
    width: number;
    height: number;
}

export interface PatternTemplate {
    id: string;
    name: string;
    rectangles: KeyColorRectangle[];
    tags: string[];
    description?: string;
    created_at: string;
    updated_at: string;
}

// ── Value Source ───────────────────────────────────────────────

export type ValueSourceType =
    | 'static' | 'animated' | 'audio'
    | 'adaptive_time' | 'adaptive_scene' | 'daylight'
    | 'static_color' | 'animated_color' | 'adaptive_time_color'
    | 'ha_entity' | 'gradient_map' | 'css_extract'
    | 'system_metrics' | 'game_event';

export interface SchedulePoint {
    time: string;
    value: number;
}

export interface ColorSchedulePoint {
    time: string;
    color: number[];
}

interface ValueSourceBase {
    id: string;
    name: string;
    source_type: ValueSourceType;
    return_type: 'float' | 'color';
    description?: string;
    tags: string[];
    created_at: string;
    updated_at: string;
}

export interface StaticValueSource extends ValueSourceBase {
    source_type: 'static';
    return_type: 'float';
    value: number;
}

export interface AnimatedValueSource extends ValueSourceBase {
    source_type: 'animated';
    return_type: 'float';
    waveform: string;
    speed: number;
    min_value: number;
    max_value: number;
}

export interface AudioValueSource extends ValueSourceBase {
    source_type: 'audio';
    return_type: 'float';
    audio_source_id: string;
    mode: string;
    sensitivity: number;
    smoothing: number;
    min_value: number;
    max_value: number;
    auto_gain: boolean;
}

export interface AdaptiveTimeValueSource extends ValueSourceBase {
    source_type: 'adaptive_time';
    return_type: 'float';
    schedule: SchedulePoint[];
    min_value: number;
    max_value: number;
}

export interface AdaptiveSceneValueSource extends ValueSourceBase {
    source_type: 'adaptive_scene';
    return_type: 'float';
    picture_source_id: string;
    scene_behavior: string;
    sensitivity: number;
    smoothing: number;
    min_value: number;
    max_value: number;
}

export interface DaylightValueSource extends ValueSourceBase {
    source_type: 'daylight';
    return_type: 'float';
    speed: number;
    use_real_time: boolean;
    latitude: number;
    min_value: number;
    max_value: number;
}

export interface StaticColorValueSource extends ValueSourceBase {
    source_type: 'static_color';
    return_type: 'color';
    color: number[];
}

export interface AnimatedColorValueSource extends ValueSourceBase {
    source_type: 'animated_color';
    return_type: 'color';
    colors: number[][];
    speed: number;
    easing: string;
}

export interface AdaptiveTimeColorValueSource extends ValueSourceBase {
    source_type: 'adaptive_time_color';
    return_type: 'color';
    schedule: ColorSchedulePoint[];
}

export interface HAEntityValueSource extends ValueSourceBase {
    source_type: 'ha_entity';
    return_type: 'float';
    ha_source_id: string;
    entity_id: string;
    attribute: string;
    min_ha_value: number;
    max_ha_value: number;
    smoothing: number;
}

export interface GradientMapValueSource extends ValueSourceBase {
    source_type: 'gradient_map';
    return_type: 'color';
    value_source_id: string;
    gradient_id: string;
    easing: string;
}

export interface CSSExtractValueSource extends ValueSourceBase {
    source_type: 'css_extract';
    return_type: 'color';
    color_strip_source_id: string;
    led_start: number;
    led_end: number;
}

export interface SystemMetricsValueSource extends ValueSourceBase {
    source_type: 'system_metrics';
    return_type: 'float';
    metric: string;
    min_value: number;
    max_value: number;
    max_rate: number;
    disk_path: string;
    sensor_label: string;
    poll_interval: number;
    smoothing: number;
}

export interface GameEventValueSource extends ValueSourceBase {
    source_type: 'game_event';
    return_type: 'float';
    game_integration_id: string;
    event_type: string;
    min_game_value: number;
    max_game_value: number;
    smoothing: number;
    default_value: number;
    timeout: number;
}

export type ValueSource =
    | StaticValueSource
    | AnimatedValueSource
    | AudioValueSource
    | AdaptiveTimeValueSource
    | AdaptiveSceneValueSource
    | DaylightValueSource
    | StaticColorValueSource
    | AnimatedColorValueSource
    | AdaptiveTimeColorValueSource
    | HAEntityValueSource
    | GradientMapValueSource
    | CSSExtractValueSource
    | SystemMetricsValueSource
    | GameEventValueSource;

// ── Audio Source ───────────────────────────────────────────────

export type AudioSourceType = 'capture' | 'processed';

interface AudioSourceBase {
    id: string;
    name: string;
    source_type: AudioSourceType;
    description?: string;
    tags: string[];
    created_at: string;
    updated_at: string;
}

export interface CaptureAudioSource extends AudioSourceBase {
    source_type: 'capture';
    device_index: number;
    is_loopback: boolean;
    audio_template_id?: string;
}

export interface ProcessedAudioSource extends AudioSourceBase {
    source_type: 'processed';
    audio_source_id: string;
    audio_processing_template_id: string;
}

export type AudioSource =
    | CaptureAudioSource
    | ProcessedAudioSource;

// ── Picture Source ─────────────────────────────────────────────

export type PictureSourceType = 'raw' | 'processed' | 'static_image' | 'video';

interface PictureSourceBase {
    id: string;
    name: string;
    stream_type: PictureSourceType;
    description?: string;
    tags: string[];
    created_at: string;
    updated_at: string;
}

export interface RawPictureSource extends PictureSourceBase {
    stream_type: 'raw';
    display_index: number;
    capture_template_id: string;
    target_fps: number;
}

export interface ProcessedPictureSource extends PictureSourceBase {
    stream_type: 'processed';
    source_stream_id: string;
    postprocessing_template_id: string;
}

export interface StaticImagePictureSource extends PictureSourceBase {
    stream_type: 'static_image';
    image_asset_id?: string;
}

export interface VideoPictureSource extends PictureSourceBase {
    stream_type: 'video';
    video_asset_id?: string;
    loop: boolean;
    playback_speed: number;
    start_time?: number;
    end_time?: number;
    resolution_limit?: number;
    clock_id?: string;
    target_fps: number;
}

export type PictureSource =
    | RawPictureSource
    | ProcessedPictureSource
    | StaticImagePictureSource
    | VideoPictureSource;

// ── Scene Preset ──────────────────────────────────────────────

export interface TargetSnapshot {
    id?: string;
    target_id: string;
    running: boolean;
    color_strip_source_id: string;
    brightness?: BindableFloat;
    fps: number;
}

export interface ScenePreset {
    id: string;
    name: string;
    description: string;
    color?: string;
    targets: TargetSnapshot[];
    order: number;
    tags: string[];
    created_at: string;
    updated_at: string;
}

// ── Sync Clock ────────────────────────────────────────────────

export interface SyncClock {
    id: string;
    name: string;
    speed: number;
    description?: string;
    tags: string[];
    is_running: boolean;
    elapsed_time: number;
    created_at: string;
    updated_at: string;
}

export interface WeatherSource {
    id: string;
    name: string;
    provider: string;
    provider_config: Record<string, any>;
    latitude: number;
    longitude: number;
    update_interval: number;
    description?: string;
    tags: string[];
    created_at: string;
    updated_at: string;
}

export interface WeatherSourceListResponse {
    sources: WeatherSource[];
    count: number;
}

// ── Home Assistant Source ────────────────────────────────────

export interface HomeAssistantSource {
    id: string;
    name: string;
    host: string;
    use_ssl: boolean;
    entity_filters: string[];
    connected: boolean;
    entity_count: number;
    description?: string;
    tags: string[];
    created_at: string;
    updated_at: string;
}

export interface HomeAssistantSourceListResponse {
    sources: HomeAssistantSource[];
    count: number;
}

export interface HomeAssistantConnectionStatus {
    source_id: string;
    name: string;
    connected: boolean;
    entity_count: number;
}

export interface HomeAssistantStatusResponse {
    connections: HomeAssistantConnectionStatus[];
    total_sources: number;
    connected_count: number;
}

// ── MQTT Source ────────────────────────────────────────────────

export interface MQTTSource {
    id: string;
    name: string;
    broker_host: string;
    broker_port: number;
    username: string;
    password_set: boolean;
    client_id: string;
    base_topic: string;
    connected: boolean;
    description?: string;
    tags: string[];
    created_at: string;
    updated_at: string;
}

export interface MQTTSourceListResponse {
    sources: MQTTSource[];
    count: number;
}

export interface MQTTConnectionStatus {
    source_id: string;
    name: string;
    connected: boolean;
    broker: string;
}

export interface MQTTStatusResponse {
    connections: MQTTConnectionStatus[];
    total_sources: number;
    connected_count: number;
}

// ── Asset ────────────────────────────────────────────────────

export interface Asset {
    id: string;
    name: string;
    filename: string;
    mime_type: string;
    asset_type: string;
    size_bytes: number;
    description?: string;
    tags: string[];
    prebuilt: boolean;
    created_at: string;
    updated_at: string;
}

export interface AssetListResponse {
    assets: Asset[];
    count: number;
}

// ── Automation ────────────────────────────────────────────────

export type RuleType =
    | 'application' | 'time_of_day' | 'system_idle'
    | 'display_state' | 'mqtt' | 'webhook' | 'startup';

export interface AutomationRule {
    rule_type: RuleType;
    apps?: string[];
    match_type?: string;
    start_time?: string;
    end_time?: string;
    idle_minutes?: number;
    when_idle?: boolean;
    state?: string;
    topic?: string;
    payload?: string;
    match_mode?: string;
    token?: string;
}

export interface Automation {
    id: string;
    name: string;
    enabled: boolean;
    rule_logic: 'or' | 'and';
    rules: AutomationRule[];
    scene_preset_id?: string;
    deactivation_mode: 'none' | 'revert' | 'fallback_scene';
    deactivation_scene_preset_id?: string;
    tags: string[];
    webhook_url?: string;
    is_active: boolean;
    last_activated_at?: string;
    last_deactivated_at?: string;
    created_at: string;
    updated_at: string;
}

// ── Templates ─────────────────────────────────────────────────

export interface FilterInstance {
    filter_id: string;
    options: Record<string, any>;
}

export interface CaptureTemplate {
    id: string;
    name: string;
    engine_type: string;
    engine_config: Record<string, any>;
    tags: string[];
    description?: string;
    created_at: string;
    updated_at: string;
}

export interface PostprocessingTemplate {
    id: string;
    name: string;
    filters: FilterInstance[];
    tags: string[];
    description?: string;
    created_at: string;
    updated_at: string;
}

export interface ColorStripProcessingTemplate {
    id: string;
    name: string;
    filters: FilterInstance[];
    tags: string[];
    description?: string;
    created_at: string;
    updated_at: string;
}

export interface AudioTemplate {
    id: string;
    name: string;
    engine_type: string;
    engine_config: Record<string, any>;
    tags: string[];
    description?: string;
    created_at: string;
    updated_at: string;
}

// ── Filter Definition (from /filters endpoint) ────────────────

export interface FilterOptionDef {
    type: string;
    default?: any;
    min?: number;
    max?: number;
    step?: number;
    choices?: string[];
    label?: string;
}

export interface FilterDef {
    id: string;
    name: string;
    description?: string;
    category?: string;
    options: Record<string, FilterOptionDef>;
}

// ── Engine Info (from /capture-engines, /audio-engines) ───────

export interface EngineInfo {
    type: string;
    name: string;
    available: boolean;
    has_own_displays?: boolean;
    default_config?: Record<string, any>;
}

// ── Display ───────────────────────────────────────────────────

export interface Display {
    index: number;
    name: string;
    width: number;
    height: number;
    x: number;
    y: number;
    is_primary: boolean;
}

// ── API List Response Wrappers ────────────────────────────────

export interface DeviceListResponse {
    devices: Device[];
    count: number;
}

export interface OutputTargetListResponse {
    targets: OutputTarget[];
    count: number;
}

export interface ColorStripSourceListResponse {
    sources: ColorStripSource[];
    count: number;
}

export interface PatternTemplateListResponse {
    templates: PatternTemplate[];
    count: number;
}

export interface ValueSourceListResponse {
    sources: ValueSource[];
    count: number;
}

export interface AudioSourceListResponse {
    sources: AudioSource[];
    count: number;
}

export interface PictureSourceListResponse {
    streams: PictureSource[];
    count: number;
}

export interface ScenePresetListResponse {
    presets: ScenePreset[];
    count: number;
}

export interface SyncClockListResponse {
    clocks: SyncClock[];
    count: number;
}

export interface AutomationListResponse {
    automations: Automation[];
    count: number;
}

// ── Game Integration ─────────────────────────────────────────

export interface GameEventMapping {
    event_type: string;
    effect_type: string;
    color: number[];
    duration_ms: number;
    intensity: number;
    priority: number;
}

export interface GameIntegration {
    id: string;
    name: string;
    adapter_type: string;
    adapter_config: Record<string, any>;
    event_mappings: GameEventMapping[];
    enabled: boolean;
    description?: string;
    tags: string[];
    created_at: string;
    updated_at: string;
}

export interface GameIntegrationListResponse {
    integrations: GameIntegration[];
    count: number;
}

export interface GameAdapterConfigField {
    name: string;
    type: string;
    label?: string;
    default?: any;
    required?: boolean;
    hint?: string;
}

export interface GameAdapterInfo {
    adapter_type: string;
    display_name: string;
    game_name: string;
    supported_events: string[];
    config_schema: GameAdapterConfigField[];
    setup_instructions?: string;
    supports_auto_setup?: boolean;
}

export interface GameAdapterListResponse {
    adapters: GameAdapterInfo[];
}

export interface GameEventRecord {
    timestamp: string;
    event_type: string;
    value?: number;
    data?: Record<string, any>;
}

export interface GameIntegrationStatus {
    integration_id: string;
    connected: boolean;
    last_event_at?: string;
    event_count: number;
    error?: string;
}

export interface EffectPreset {
    key: string;
    name: string;
    description: string;
    target_game_types: string[];
    event_mappings: GameEventMapping[];
}

// ── Component Option Types (re-exported from authoritative sources) ───

export type { IconSelectItem, IconSelectOpts } from './core/icon-select.ts';
export type { EntitySelectOpts } from './core/entity-palette.ts';
export type { BulkAction, CardItem, CardSectionOpts } from './core/card-sections.ts';
export type { FilterListOpts } from './core/filter-list.ts';
