"""Output target storage using SQLite."""

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

from ledgrab.storage.base_sqlite_store import BaseSqliteStore
from ledgrab.storage.bindable import BindableFloat
from ledgrab.storage.database import Database
from ledgrab.storage.output_target import OutputTarget
from ledgrab.storage.wled_output_target import WledOutputTarget
from ledgrab.storage.ha_light_output_target import (
    HALightMapping,
    HALightOutputTarget,
)
from ledgrab.utils import get_logger

logger = get_logger(__name__)

DEFAULT_STATE_CHECK_INTERVAL = 30  # seconds


class OutputTargetStore(BaseSqliteStore[OutputTarget]):
    """Persistent storage for output targets."""

    _table_name = "output_targets"
    _entity_name = "Output target"

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

    # Backward-compatible aliases
    get_all_targets = BaseSqliteStore.get_all
    get_target = BaseSqliteStore.get
    delete_target = BaseSqliteStore.delete

    def create_target(
        self,
        name: str,
        target_type: str,
        device_id: str = "",
        color_strip_source_id: str = "",
        brightness=None,
        fps: int = 30,
        keepalive_interval: float = 1.0,
        state_check_interval: int = DEFAULT_STATE_CHECK_INTERVAL,
        min_brightness_threshold: int = 0,
        adaptive_fps: bool = False,
        protocol: str = "ddp",
        description: Optional[str] = None,
        tags: Optional[List[str]] = None,
        ha_source_id: str = "",
        ha_light_mappings: Optional[List[HALightMapping]] = None,
        update_rate: float = 2.0,
        transition=None,
        color_tolerance: int = 5,
        # legacy compat
        brightness_value_source_id: str = "",
    ) -> OutputTarget:
        """Create a new output target.

        Raises:
            ValueError: If validation fails
        """
        if target_type not in ("led", "ha_light"):
            raise ValueError(f"Invalid target type: {target_type}")

        # Check for duplicate name
        for target in self._items.values():
            if target.name == name:
                raise ValueError(f"Output target with name '{name}' already exists")

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

        # Resolve brightness to BindableFloat
        if isinstance(brightness, BindableFloat):
            bright = brightness
        elif brightness is not None:
            bright = BindableFloat.from_raw(brightness, default=1.0)
        elif brightness_value_source_id:
            bright = BindableFloat(1.0, source_id=brightness_value_source_id)
        else:
            bright = BindableFloat(1.0)

        if target_type == "led":
            target: OutputTarget = WledOutputTarget(
                id=target_id,
                name=name,
                target_type="led",
                device_id=device_id,
                color_strip_source_id=color_strip_source_id,
                brightness=bright,
                fps=BindableFloat.from_raw(fps, default=30.0),
                keepalive_interval=keepalive_interval,
                state_check_interval=state_check_interval,
                min_brightness_threshold=BindableFloat.from_raw(
                    min_brightness_threshold, default=0.0
                ),
                adaptive_fps=adaptive_fps,
                protocol=protocol,
                description=description,
                created_at=now,
                updated_at=now,
            )
        elif target_type == "ha_light":
            # Resolve transition
            if isinstance(transition, BindableFloat):
                trans = transition
            elif transition is not None:
                trans = BindableFloat.from_raw(transition, default=0.5)
            else:
                trans = BindableFloat(0.5)

            target = HALightOutputTarget(
                id=target_id,
                name=name,
                target_type="ha_light",
                ha_source_id=ha_source_id,
                color_strip_source_id=color_strip_source_id,
                brightness=bright,
                light_mappings=ha_light_mappings or [],
                update_rate=BindableFloat.from_raw(update_rate, default=2.0),
                transition=trans,
                min_brightness_threshold=BindableFloat.from_raw(
                    min_brightness_threshold, default=0.0
                ),
                color_tolerance=BindableFloat.from_raw(color_tolerance, default=5.0),
                description=description,
                created_at=now,
                updated_at=now,
            )
        else:
            raise ValueError(f"Unknown target type: {target_type}")

        target.tags = tags or []
        self._items[target_id] = target
        self._save_item(target_id, target)

        logger.info(f"Created output target: {name} ({target_id}, type={target_type})")
        return target

    def update_target(
        self,
        target_id: str,
        name=None,
        device_id=None,
        color_strip_source_id=None,
        brightness=None,
        fps=None,
        keepalive_interval=None,
        state_check_interval=None,
        min_brightness_threshold=None,
        adaptive_fps=None,
        protocol=None,
        description=None,
        tags=None,
        ha_source_id=None,
        ha_light_mappings=None,
        update_rate=None,
        transition=None,
        color_tolerance=None,
        # legacy compat
        brightness_value_source_id=None,
    ) -> OutputTarget:
        """Update an output target.

        Raises:
            ValueError: If target not found or validation fails
        """
        if target_id not in self._items:
            raise ValueError(f"Output target not found: {target_id}")

        target = self._items[target_id]

        if name is not None:
            # Check for duplicate name (exclude self)
            for other in self._items.values():
                if other.id != target_id and other.name == name:
                    raise ValueError(f"Output target with name '{name}' already exists")

        target.update_fields(
            name=name,
            device_id=device_id,
            color_strip_source_id=color_strip_source_id,
            brightness=brightness,
            brightness_value_source_id=brightness_value_source_id,
            fps=fps,
            keepalive_interval=keepalive_interval,
            state_check_interval=state_check_interval,
            min_brightness_threshold=min_brightness_threshold,
            adaptive_fps=adaptive_fps,
            protocol=protocol,
            description=description,
            tags=tags,
            ha_source_id=ha_source_id,
            light_mappings=ha_light_mappings,
            update_rate=update_rate,
            transition=transition,
            color_tolerance=color_tolerance,
        )

        target.updated_at = datetime.now(timezone.utc)
        self._save_item(target_id, target)

        logger.info(f"Updated output target: {target_id}")
        return target

    def get_targets_for_device(self, device_id: str) -> List[OutputTarget]:
        """Get all targets that reference a specific device."""
        return [
            t
            for t in self._items.values()
            if isinstance(t, WledOutputTarget) and t.device_id == device_id
        ]

    def get_targets_referencing_css(self, css_id: str) -> List[str]:
        """Return names of targets that reference a color strip source."""
        result = []
        for target in self._items.values():
            if isinstance(target, WledOutputTarget) and target.color_strip_source_id == css_id:
                result.append(target.name)
            elif isinstance(target, HALightOutputTarget) and target.color_strip_source_id == css_id:
                result.append(target.name)
        return result

    def count(self) -> int:
        """Get number of targets."""
        return len(self._items)
