"""Color strip processing template storage using SQLite."""

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

from wled_controller.core.filters.filter_instance import FilterInstance
from wled_controller.core.filters.registry import FilterRegistry
from wled_controller.storage.base_sqlite_store import BaseSqliteStore
from wled_controller.storage.color_strip_processing_template import ColorStripProcessingTemplate
from wled_controller.storage.database import Database
from wled_controller.utils import get_logger

logger = get_logger(__name__)


class ColorStripProcessingTemplateStore(BaseSqliteStore[ColorStripProcessingTemplate]):
    """Storage for color strip processing templates.

    All templates are persisted to the database.
    On startup, if no templates exist, a default one is auto-created.
    """

    _table_name = "color_strip_processing_templates"
    _entity_name = "Color strip processing template"
    _version = "1.0.0"

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

    # Backward-compatible aliases
    get_all_templates = BaseSqliteStore.get_all
    get_template = BaseSqliteStore.get
    delete_template = BaseSqliteStore.delete

    def _ensure_initial_template(self) -> None:
        """Auto-create a default color strip processing template if none exist."""
        if self._items:
            return

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

        template = ColorStripProcessingTemplate(
            id=template_id,
            name="Default",
            filters=[
                FilterInstance("brightness", {"value": 1.0}),
                FilterInstance("gamma", {"value": 2.2}),
            ],
            created_at=now,
            updated_at=now,
            description="Default color strip processing template",
        )

        self._items[template_id] = template
        self._save_item(template_id, template)
        logger.info(f"Auto-created initial color strip processing template: {template.name} ({template_id})")

    def _validate_strip_filters(self, filters: List[FilterInstance]) -> None:
        """Validate that all filters support strip processing."""
        for fi in filters:
            if not FilterRegistry.is_registered(fi.filter_id):
                raise ValueError(f"Unknown filter type: '{fi.filter_id}'")
            filter_cls = FilterRegistry.get(fi.filter_id)
            if not getattr(filter_cls, "supports_strip", True):
                raise ValueError(
                    f"Filter '{fi.filter_id}' does not support strip processing"
                )

    def create_template(
        self,
        name: str,
        filters: Optional[List[FilterInstance]] = None,
        description: Optional[str] = None,
        tags: Optional[List[str]] = None,
    ) -> ColorStripProcessingTemplate:
        self._check_name_unique(name)

        if filters is None:
            filters = []

        self._validate_strip_filters(filters)

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

        template = ColorStripProcessingTemplate(
            id=template_id,
            name=name,
            filters=filters,
            created_at=now,
            updated_at=now,
            description=description,
            tags=tags or [],
        )

        self._items[template_id] = template
        self._save_item(template_id, template)

        logger.info(f"Created color strip processing template: {name} ({template_id})")
        return template

    def update_template(
        self,
        template_id: str,
        name: Optional[str] = None,
        filters: Optional[List[FilterInstance]] = None,
        description: Optional[str] = None,
        tags: Optional[List[str]] = None,
    ) -> ColorStripProcessingTemplate:
        template = self.get(template_id)

        if name is not None:
            self._check_name_unique(name, exclude_id=template_id)
            template.name = name
        if filters is not None:
            self._validate_strip_filters(filters)
            template.filters = filters
        if description is not None:
            template.description = description
        if tags is not None:
            template.tags = tags

        template.updated_at = datetime.now(timezone.utc)
        self._save_item(template_id, template)

        logger.info(f"Updated color strip processing template: {template_id}")
        return template

    def resolve_filter_instances(self, filter_instances, _visited=None):
        """Recursively resolve filter instances, expanding css_filter_template references.

        Returns a flat list of FilterInstance objects with no css_filter_template entries.
        """
        if _visited is None:
            _visited = set()
        resolved = []
        for fi in filter_instances:
            if fi.filter_id == "css_filter_template":
                template_id = fi.options.get("template_id", "")
                if not template_id or template_id in _visited:
                    continue
                try:
                    ref_template = self.get_template(template_id)
                    _visited.add(template_id)
                    resolved.extend(self.resolve_filter_instances(ref_template.filters, _visited))
                    _visited.discard(template_id)
                except ValueError:
                    logger.warning(f"Referenced CSS filter template '{template_id}' not found, skipping")
            else:
                resolved.append(fi)
        return resolved

    def get_references(self, template_id: str, device_store=None, css_store=None) -> List[str]:
        """Return names of entities that reference this template."""
        refs = []
        if device_store:
            for dev in device_store.get_all():
                if getattr(dev, "default_css_processing_template_id", "") == template_id:
                    refs.append(f"Device: {dev.name}")
        if css_store:
            for src in css_store.get_all():
                layers = getattr(src, "layers", None)
                if layers:
                    for layer in layers:
                        if isinstance(layer, dict) and layer.get("processing_template_id") == template_id:
                            refs.append(f"Composite layer in: {src.name}")
                            break
        return refs
