"""Color strip source storage using SQLite."""

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

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.color_strip_source import (
    ColorStripSource,
    CompositeColorStripSource,
    MappedColorStripSource,
    ProcessedColorStripSource,
)
from wled_controller.utils import get_logger

logger = get_logger(__name__)


class ColorStripStore(BaseSqliteStore[ColorStripSource]):
    """Persistent storage for color strip sources."""

    _table_name = "color_strip_sources"
    _entity_name = "Color strip source"

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

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

    def get_source(self, source_id: str) -> ColorStripSource:
        """Get a color strip source by ID (alias for get())."""
        return self.get(source_id)

    def create_source(self, name: str, source_type: str = "picture",
                      **kwargs) -> ColorStripSource:
        """Create a new color strip source.

        All type-specific parameters are passed as keyword arguments and
        forwarded to the subclass ``create_from_kwargs`` factory method.

        Raises:
            ValueError: If validation fails
        """
        if not name or not name.strip():
            raise ValueError("Name is required")

        for source in self._items.values():
            if source.name == name:
                raise ValueError(f"Color strip source with name '{name}' already exists")

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

        tags = kwargs.pop("tags", None) or []

        source = ColorStripSource.create_instance(
            source_type,
            id=source_id,
            name=name,
            created_at=now,
            updated_at=now,
            tags=tags,
            **kwargs,
        )

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

        logger.info(f"Created color strip source: {name} ({source_id}, type={source_type})")
        return source

    def update_source(self, source_id: str, **kwargs) -> ColorStripSource:
        """Update an existing color strip source.

        All type-specific parameters are passed as keyword arguments and
        forwarded to the subclass ``apply_update`` method.

        Raises:
            ValueError: If source not found
        """
        if source_id not in self._items:
            raise ValueError(f"Color strip source not found: {source_id}")

        source = self._items[source_id]

        # -- Common fields handled here (before dispatching to subclass) --
        name = kwargs.pop("name", None)
        if name is not None:
            for other in self._items.values():
                if other.id != source_id and other.name == name:
                    raise ValueError(f"Color strip source with name '{name}' already exists")
            source.name = name

        description = kwargs.pop("description", None)
        if description is not None:
            source.description = description

        clock_id = kwargs.pop("clock_id", None)
        if clock_id is not None:
            source.clock_id = resolve_ref(clock_id, source.clock_id)

        tags = kwargs.pop("tags", None)
        if tags is not None:
            source.tags = tags

        # -- Type-specific fields --
        source.apply_update(**kwargs)

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

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

    def get_composites_referencing(self, source_id: str) -> List[str]:
        """Return names of composite sources that reference a given source as a layer."""
        names = []
        for source in self._items.values():
            if isinstance(source, CompositeColorStripSource):
                for layer in source.layers:
                    if layer.get("source_id") == source_id:
                        names.append(source.name)
                        break
        return names

    def get_mapped_referencing(self, source_id: str) -> List[str]:
        """Return names of mapped sources that reference a given source as a zone."""
        names = []
        for source in self._items.values():
            if isinstance(source, MappedColorStripSource):
                for zone in source.zones:
                    if zone.get("source_id") == source_id:
                        names.append(source.name)
                        break
        return names

    def get_processed_referencing(self, source_id: str) -> List[str]:
        """Return names of processed sources that reference a given source as input."""
        names = []
        for source in self._items.values():
            if isinstance(source, ProcessedColorStripSource):
                if source.input_source_id == source_id:
                    names.append(source.name)
        return names
