"""Value source storage using SQLite."""

import uuid
from datetime import datetime, timezone
from typing import List, Optional

from wled_controller.storage.base_sqlite_store import BaseSqliteStore
from wled_controller.storage.database import Database
from wled_controller.storage.utils import resolve_ref
from wled_controller.storage.value_source import (
    AdaptiveValueSource,
    AnimatedValueSource,
    AudioValueSource,
    DaylightValueSource,
    StaticValueSource,
    ValueSource,
)
from wled_controller.utils import get_logger

logger = get_logger(__name__)


class ValueSourceStore(BaseSqliteStore[ValueSource]):
    """Persistent storage for value sources."""

    _table_name = "value_sources"
    _entity_name = "Value source"

    def __init__(self, db: Database):
        super().__init__(db, ValueSource.from_dict)

    # Backward-compatible aliases
    get_all_sources = BaseSqliteStore.get_all
    get_source = BaseSqliteStore.get
    delete_source = BaseSqliteStore.delete

    # ── CRUD ─────────────────────────────────────────────────────────

    def create_source(
        self,
        name: str,
        source_type: str,
        value: Optional[float] = None,
        waveform: Optional[str] = None,
        speed: Optional[float] = None,
        min_value: Optional[float] = None,
        max_value: Optional[float] = None,
        audio_source_id: Optional[str] = None,
        mode: Optional[str] = None,
        sensitivity: Optional[float] = None,
        smoothing: Optional[float] = None,
        description: Optional[str] = None,
        schedule: Optional[list] = None,
        picture_source_id: Optional[str] = None,
        scene_behavior: Optional[str] = None,
        auto_gain: Optional[bool] = None,
        use_real_time: Optional[bool] = None,
        latitude: Optional[float] = None,
        tags: Optional[List[str]] = None,
    ) -> ValueSource:
        if source_type not in ("static", "animated", "audio", "adaptive_time", "adaptive_scene", "daylight"):
            raise ValueError(f"Invalid source type: {source_type}")

        self._check_name_unique(name)

        sid = f"vs_{uuid.uuid4().hex[:8]}"
        now = datetime.now(timezone.utc)

        common_tags = tags or []

        if source_type == "static":
            source: ValueSource = StaticValueSource(
                id=sid, name=name, source_type="static",
                created_at=now, updated_at=now, description=description, tags=common_tags,
                value=value if value is not None else 1.0,
            )
        elif source_type == "animated":
            source = AnimatedValueSource(
                id=sid, name=name, source_type="animated",
                created_at=now, updated_at=now, description=description, tags=common_tags,
                waveform=waveform or "sine",
                speed=speed if speed is not None else 10.0,
                min_value=min_value if min_value is not None else 0.0,
                max_value=max_value if max_value is not None else 1.0,
            )
        elif source_type == "audio":
            source = AudioValueSource(
                id=sid, name=name, source_type="audio",
                created_at=now, updated_at=now, description=description, tags=common_tags,
                audio_source_id=audio_source_id or "",
                mode=mode or "rms",
                sensitivity=sensitivity if sensitivity is not None else 1.0,
                smoothing=smoothing if smoothing is not None else 0.3,
                min_value=min_value if min_value is not None else 0.0,
                max_value=max_value if max_value is not None else 1.0,
                auto_gain=bool(auto_gain) if auto_gain is not None else False,
            )
        elif source_type == "adaptive_time":
            schedule_data = schedule or []
            if len(schedule_data) < 2:
                raise ValueError("Time of day schedule requires at least 2 points")
            source = AdaptiveValueSource(
                id=sid, name=name, source_type="adaptive_time",
                created_at=now, updated_at=now, description=description, tags=common_tags,
                schedule=schedule_data,
                min_value=min_value if min_value is not None else 0.0,
                max_value=max_value if max_value is not None else 1.0,
            )
        elif source_type == "adaptive_scene":
            source = AdaptiveValueSource(
                id=sid, name=name, source_type="adaptive_scene",
                created_at=now, updated_at=now, description=description, tags=common_tags,
                picture_source_id=picture_source_id or "",
                scene_behavior=scene_behavior or "complement",
                sensitivity=sensitivity if sensitivity is not None else 1.0,
                smoothing=smoothing if smoothing is not None else 0.3,
                min_value=min_value if min_value is not None else 0.0,
                max_value=max_value if max_value is not None else 1.0,
            )
        elif source_type == "daylight":
            source = DaylightValueSource(
                id=sid, name=name, source_type="daylight",
                created_at=now, updated_at=now, description=description, tags=common_tags,
                speed=speed if speed is not None else 1.0,
                use_real_time=bool(use_real_time) if use_real_time is not None else False,
                latitude=latitude if latitude is not None else 50.0,
                min_value=min_value if min_value is not None else 0.0,
                max_value=max_value if max_value is not None else 1.0,
            )

        self._items[sid] = source
        self._save_item(sid, source)

        logger.info(f"Created value source: {name} ({sid}, type={source_type})")
        return source

    def update_source(
        self,
        source_id: str,
        name: Optional[str] = None,
        value: Optional[float] = None,
        waveform: Optional[str] = None,
        speed: Optional[float] = None,
        min_value: Optional[float] = None,
        max_value: Optional[float] = None,
        audio_source_id: Optional[str] = None,
        mode: Optional[str] = None,
        sensitivity: Optional[float] = None,
        smoothing: Optional[float] = None,
        description: Optional[str] = None,
        schedule: Optional[list] = None,
        picture_source_id: Optional[str] = None,
        scene_behavior: Optional[str] = None,
        auto_gain: Optional[bool] = None,
        use_real_time: Optional[bool] = None,
        latitude: Optional[float] = None,
        tags: Optional[List[str]] = None,
    ) -> ValueSource:
        source = self.get(source_id)

        if name is not None:
            self._check_name_unique(name, exclude_id=source_id)
            source.name = name

        if description is not None:
            source.description = description
        if tags is not None:
            source.tags = tags

        if isinstance(source, StaticValueSource):
            if value is not None:
                source.value = value
        elif isinstance(source, AnimatedValueSource):
            if waveform is not None:
                source.waveform = waveform
            if speed is not None:
                source.speed = speed
            if min_value is not None:
                source.min_value = min_value
            if max_value is not None:
                source.max_value = max_value
        elif isinstance(source, AudioValueSource):
            if audio_source_id is not None:
                source.audio_source_id = resolve_ref(audio_source_id, source.audio_source_id)
            if mode is not None:
                source.mode = mode
            if sensitivity is not None:
                source.sensitivity = sensitivity
            if smoothing is not None:
                source.smoothing = smoothing
            if min_value is not None:
                source.min_value = min_value
            if max_value is not None:
                source.max_value = max_value
            if auto_gain is not None:
                source.auto_gain = auto_gain
        elif isinstance(source, AdaptiveValueSource):
            if schedule is not None:
                if source.source_type == "adaptive_time" and len(schedule) < 2:
                    raise ValueError("Time of day schedule requires at least 2 points")
                source.schedule = schedule
            if picture_source_id is not None:
                source.picture_source_id = resolve_ref(picture_source_id, source.picture_source_id)
            if scene_behavior is not None:
                source.scene_behavior = scene_behavior
            if sensitivity is not None:
                source.sensitivity = sensitivity
            if smoothing is not None:
                source.smoothing = smoothing
            if min_value is not None:
                source.min_value = min_value
            if max_value is not None:
                source.max_value = max_value
        elif isinstance(source, DaylightValueSource):
            if speed is not None:
                source.speed = speed
            if use_real_time is not None:
                source.use_real_time = use_real_time
            if latitude is not None:
                source.latitude = latitude
            if min_value is not None:
                source.min_value = min_value
            if max_value is not None:
                source.max_value = max_value

        source.updated_at = datetime.now(timezone.utc)
        self._save_item(source_id, source)

        logger.info(f"Updated value source: {source_id}")
        return source
