"""Sync clock routes: CRUD + runtime control for synchronization clocks."""

from fastapi import APIRouter, Depends, HTTPException

from wled_controller.api.auth import AuthRequired
from wled_controller.api.dependencies import (
    fire_entity_event,
    get_color_strip_store,
    get_sync_clock_manager,
    get_sync_clock_store,
)
from wled_controller.api.schemas.sync_clocks import (
    SyncClockCreate,
    SyncClockListResponse,
    SyncClockResponse,
    SyncClockUpdate,
)
from wled_controller.storage.sync_clock import SyncClock
from wled_controller.storage.sync_clock_store import SyncClockStore
from wled_controller.storage.color_strip_store import ColorStripStore
from wled_controller.core.processing.sync_clock_manager import SyncClockManager
from wled_controller.utils import get_logger
from wled_controller.storage.base_store import EntityNotFoundError

logger = get_logger(__name__)

router = APIRouter()


def _to_response(clock: SyncClock, manager: SyncClockManager) -> SyncClockResponse:
    """Convert a SyncClock to a SyncClockResponse (with runtime state)."""
    rt = manager.get_runtime(clock.id)
    return SyncClockResponse(
        id=clock.id,
        name=clock.name,
        speed=rt.speed if rt else clock.speed,
        description=clock.description,
        tags=clock.tags,
        is_running=rt.is_running if rt else True,
        elapsed_time=rt.get_time() if rt else 0.0,
        created_at=clock.created_at,
        updated_at=clock.updated_at,
    )


@router.get("/api/v1/sync-clocks", response_model=SyncClockListResponse, tags=["Sync Clocks"])
async def list_sync_clocks(
    _auth: AuthRequired,
    store: SyncClockStore = Depends(get_sync_clock_store),
    manager: SyncClockManager = Depends(get_sync_clock_manager),
):
    """List all synchronization clocks."""
    clocks = store.get_all_clocks()
    return SyncClockListResponse(
        clocks=[_to_response(c, manager) for c in clocks],
        count=len(clocks),
    )


@router.post("/api/v1/sync-clocks", response_model=SyncClockResponse, status_code=201, tags=["Sync Clocks"])
async def create_sync_clock(
    data: SyncClockCreate,
    _auth: AuthRequired,
    store: SyncClockStore = Depends(get_sync_clock_store),
    manager: SyncClockManager = Depends(get_sync_clock_manager),
):
    """Create a new synchronization clock."""
    try:
        clock = store.create_clock(
            name=data.name,
            speed=data.speed,
            description=data.description,
            tags=data.tags,
        )
        fire_entity_event("sync_clock", "created", clock.id)
        return _to_response(clock, manager)
    except EntityNotFoundError as e:
        raise HTTPException(status_code=404, detail=str(e))

    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))


@router.get("/api/v1/sync-clocks/{clock_id}", response_model=SyncClockResponse, tags=["Sync Clocks"])
async def get_sync_clock(
    clock_id: str,
    _auth: AuthRequired,
    store: SyncClockStore = Depends(get_sync_clock_store),
    manager: SyncClockManager = Depends(get_sync_clock_manager),
):
    """Get a synchronization clock by ID."""
    try:
        clock = store.get_clock(clock_id)
        return _to_response(clock, manager)
    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e))


@router.put("/api/v1/sync-clocks/{clock_id}", response_model=SyncClockResponse, tags=["Sync Clocks"])
async def update_sync_clock(
    clock_id: str,
    data: SyncClockUpdate,
    _auth: AuthRequired,
    store: SyncClockStore = Depends(get_sync_clock_store),
    manager: SyncClockManager = Depends(get_sync_clock_manager),
):
    """Update a synchronization clock.  Speed changes are hot-applied to running streams."""
    try:
        clock = store.update_clock(
            clock_id=clock_id,
            name=data.name,
            speed=data.speed,
            description=data.description,
            tags=data.tags,
        )
        # Hot-update runtime speed
        if data.speed is not None:
            manager.update_speed(clock_id, clock.speed)
        fire_entity_event("sync_clock", "updated", clock_id)
        return _to_response(clock, manager)
    except EntityNotFoundError as e:
        raise HTTPException(status_code=404, detail=str(e))

    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))


@router.delete("/api/v1/sync-clocks/{clock_id}", status_code=204, tags=["Sync Clocks"])
async def delete_sync_clock(
    clock_id: str,
    _auth: AuthRequired,
    store: SyncClockStore = Depends(get_sync_clock_store),
    css_store: ColorStripStore = Depends(get_color_strip_store),
    manager: SyncClockManager = Depends(get_sync_clock_manager),
):
    """Delete a synchronization clock (fails if referenced by CSS sources)."""
    try:
        # Check references
        for source in css_store.get_all_sources():
            if getattr(source, "clock_id", None) == clock_id:
                raise ValueError(
                    f"Cannot delete: referenced by color strip source '{source.name}'"
                )
        manager.release_all_for(clock_id)
        store.delete_clock(clock_id)
        fire_entity_event("sync_clock", "deleted", clock_id)
    except EntityNotFoundError as e:
        raise HTTPException(status_code=404, detail=str(e))

    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))


# ── Runtime control ──────────────────────────────────────────────────

@router.post("/api/v1/sync-clocks/{clock_id}/pause", response_model=SyncClockResponse, tags=["Sync Clocks"])
async def pause_sync_clock(
    clock_id: str,
    _auth: AuthRequired,
    store: SyncClockStore = Depends(get_sync_clock_store),
    manager: SyncClockManager = Depends(get_sync_clock_manager),
):
    """Pause a synchronization clock — all linked animations freeze."""
    try:
        clock = store.get_clock(clock_id)
    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e))
    manager.pause(clock_id)
    fire_entity_event("sync_clock", "updated", clock_id)
    return _to_response(clock, manager)


@router.post("/api/v1/sync-clocks/{clock_id}/resume", response_model=SyncClockResponse, tags=["Sync Clocks"])
async def resume_sync_clock(
    clock_id: str,
    _auth: AuthRequired,
    store: SyncClockStore = Depends(get_sync_clock_store),
    manager: SyncClockManager = Depends(get_sync_clock_manager),
):
    """Resume a paused synchronization clock."""
    try:
        clock = store.get_clock(clock_id)
    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e))
    manager.resume(clock_id)
    fire_entity_event("sync_clock", "updated", clock_id)
    return _to_response(clock, manager)


@router.post("/api/v1/sync-clocks/{clock_id}/reset", response_model=SyncClockResponse, tags=["Sync Clocks"])
async def reset_sync_clock(
    clock_id: str,
    _auth: AuthRequired,
    store: SyncClockStore = Depends(get_sync_clock_store),
    manager: SyncClockManager = Depends(get_sync_clock_manager),
):
    """Reset a synchronization clock to t=0 — all linked animations restart."""
    try:
        clock = store.get_clock(clock_id)
    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e))
    manager.reset(clock_id)
    fire_entity_event("sync_clock", "updated", clock_id)
    return _to_response(clock, manager)
