"""Home Assistant source routes: CRUD + test + entity list + status."""

import asyncio
import json

from fastapi import APIRouter, Depends, HTTPException

from wled_controller.api.auth import AuthRequired
from wled_controller.api.dependencies import (
    fire_entity_event,
    get_ha_manager,
    get_ha_store,
)
from wled_controller.api.schemas.home_assistant import (
    HomeAssistantConnectionStatus,
    HomeAssistantEntityListResponse,
    HomeAssistantEntityResponse,
    HomeAssistantSourceCreate,
    HomeAssistantSourceListResponse,
    HomeAssistantSourceResponse,
    HomeAssistantSourceUpdate,
    HomeAssistantStatusResponse,
    HomeAssistantTestResponse,
)
from wled_controller.core.home_assistant.ha_manager import HomeAssistantManager
from wled_controller.core.home_assistant.ha_runtime import HARuntime
from wled_controller.storage.base_store import EntityNotFoundError
from wled_controller.storage.home_assistant_source import HomeAssistantSource
from wled_controller.storage.home_assistant_store import HomeAssistantStore
from wled_controller.utils import get_logger

logger = get_logger(__name__)

router = APIRouter()


def _to_response(
    source: HomeAssistantSource, manager: HomeAssistantManager
) -> HomeAssistantSourceResponse:
    runtime = manager.get_runtime(source.id)
    return HomeAssistantSourceResponse(
        id=source.id,
        name=source.name,
        host=source.host,
        use_ssl=source.use_ssl,
        entity_filters=source.entity_filters,
        connected=runtime.is_connected if runtime else False,
        entity_count=len(runtime.get_all_states()) if runtime else 0,
        description=source.description,
        tags=source.tags,
        created_at=source.created_at,
        updated_at=source.updated_at,
    )


@router.get(
    "/api/v1/home-assistant/sources",
    response_model=HomeAssistantSourceListResponse,
    tags=["Home Assistant"],
)
async def list_ha_sources(
    _auth: AuthRequired,
    store: HomeAssistantStore = Depends(get_ha_store),
    manager: HomeAssistantManager = Depends(get_ha_manager),
):
    sources = store.get_all_sources()
    return HomeAssistantSourceListResponse(
        sources=[_to_response(s, manager) for s in sources],
        count=len(sources),
    )


@router.post(
    "/api/v1/home-assistant/sources",
    response_model=HomeAssistantSourceResponse,
    status_code=201,
    tags=["Home Assistant"],
)
async def create_ha_source(
    data: HomeAssistantSourceCreate,
    _auth: AuthRequired,
    store: HomeAssistantStore = Depends(get_ha_store),
    manager: HomeAssistantManager = Depends(get_ha_manager),
):
    try:
        source = store.create_source(
            name=data.name,
            host=data.host,
            token=data.token,
            use_ssl=data.use_ssl,
            entity_filters=data.entity_filters,
            description=data.description,
            tags=data.tags,
        )
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    fire_entity_event("home_assistant_source", "created", source.id)
    return _to_response(source, manager)


@router.get(
    "/api/v1/home-assistant/sources/{source_id}",
    response_model=HomeAssistantSourceResponse,
    tags=["Home Assistant"],
)
async def get_ha_source(
    source_id: str,
    _auth: AuthRequired,
    store: HomeAssistantStore = Depends(get_ha_store),
    manager: HomeAssistantManager = Depends(get_ha_manager),
):
    try:
        source = store.get_source(source_id)
    except EntityNotFoundError:
        raise HTTPException(status_code=404, detail=f"Home Assistant source {source_id} not found")
    return _to_response(source, manager)


@router.put(
    "/api/v1/home-assistant/sources/{source_id}",
    response_model=HomeAssistantSourceResponse,
    tags=["Home Assistant"],
)
async def update_ha_source(
    source_id: str,
    data: HomeAssistantSourceUpdate,
    _auth: AuthRequired,
    store: HomeAssistantStore = Depends(get_ha_store),
    manager: HomeAssistantManager = Depends(get_ha_manager),
):
    try:
        source = store.update_source(
            source_id,
            name=data.name,
            host=data.host,
            token=data.token,
            use_ssl=data.use_ssl,
            entity_filters=data.entity_filters,
            description=data.description,
            tags=data.tags,
        )
    except EntityNotFoundError:
        raise HTTPException(status_code=404, detail=f"Home Assistant source {source_id} not found")
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    await manager.update_source(source_id)
    fire_entity_event("home_assistant_source", "updated", source.id)
    return _to_response(source, manager)


@router.delete(
    "/api/v1/home-assistant/sources/{source_id}", status_code=204, tags=["Home Assistant"]
)
async def delete_ha_source(
    source_id: str,
    _auth: AuthRequired,
    store: HomeAssistantStore = Depends(get_ha_store),
    manager: HomeAssistantManager = Depends(get_ha_manager),
):
    try:
        store.delete_source(source_id)
    except EntityNotFoundError:
        raise HTTPException(status_code=404, detail=f"Home Assistant source {source_id} not found")
    # Release any active runtime
    await manager.release(source_id)
    fire_entity_event("home_assistant_source", "deleted", source_id)


@router.get(
    "/api/v1/home-assistant/sources/{source_id}/entities",
    response_model=HomeAssistantEntityListResponse,
    tags=["Home Assistant"],
)
async def list_ha_entities(
    source_id: str,
    _auth: AuthRequired,
    store: HomeAssistantStore = Depends(get_ha_store),
    manager: HomeAssistantManager = Depends(get_ha_manager),
):
    """List available entities from a HA instance (live query)."""
    try:
        source = store.get_source(source_id)
    except EntityNotFoundError:
        raise HTTPException(status_code=404, detail=f"Home Assistant source {source_id} not found")

    # Try cached states first from running runtime
    runtime = manager.get_runtime(source_id)
    if runtime and runtime.is_connected:
        states = runtime.get_all_states()
        entities = [
            HomeAssistantEntityResponse(
                entity_id=s.entity_id,
                state=s.state,
                friendly_name=s.attributes.get("friendly_name", s.entity_id),
                domain=s.entity_id.split(".")[0] if "." in s.entity_id else "",
            )
            for s in states.values()
        ]
        return HomeAssistantEntityListResponse(entities=entities, count=len(entities))

    # No active runtime — do a one-shot fetch
    temp_runtime = HARuntime(source)
    try:
        raw_entities = await temp_runtime.fetch_entities()
    finally:
        await temp_runtime.stop()

    entities = [HomeAssistantEntityResponse(**e) for e in raw_entities]
    return HomeAssistantEntityListResponse(entities=entities, count=len(entities))


@router.post(
    "/api/v1/home-assistant/sources/{source_id}/test",
    response_model=HomeAssistantTestResponse,
    tags=["Home Assistant"],
)
async def test_ha_source(
    source_id: str,
    _auth: AuthRequired,
    store: HomeAssistantStore = Depends(get_ha_store),
):
    """Test connection to a Home Assistant instance."""
    try:
        source = store.get_source(source_id)
    except EntityNotFoundError:
        raise HTTPException(status_code=404, detail=f"Home Assistant source {source_id} not found")

    try:
        import websockets
    except ImportError:
        return HomeAssistantTestResponse(
            success=False,
            error="websockets package not installed",
        )

    try:
        async with websockets.connect(source.ws_url) as ws:
            # Wait for auth_required
            msg = json.loads(await asyncio.wait_for(ws.recv(), timeout=10.0))
            if msg.get("type") != "auth_required":
                return HomeAssistantTestResponse(
                    success=False, error=f"Unexpected message: {msg.get('type')}"
                )

            # Auth
            await ws.send(json.dumps({"type": "auth", "access_token": source.token}))
            msg = json.loads(await asyncio.wait_for(ws.recv(), timeout=10.0))
            if msg.get("type") != "auth_ok":
                return HomeAssistantTestResponse(
                    success=False, error=msg.get("message", "Auth failed")
                )

            ha_version = msg.get("ha_version")

            # Get entity count
            await ws.send(json.dumps({"id": 1, "type": "get_states"}))
            msg = json.loads(await asyncio.wait_for(ws.recv(), timeout=10.0))
            entity_count = len(msg.get("result", [])) if msg.get("success") else 0

            return HomeAssistantTestResponse(
                success=True,
                ha_version=ha_version,
                entity_count=entity_count,
            )
    except Exception as e:
        return HomeAssistantTestResponse(success=False, error=str(e))


@router.get(
    "/api/v1/home-assistant/status",
    response_model=HomeAssistantStatusResponse,
    tags=["Home Assistant"],
)
async def get_ha_status(
    _auth: AuthRequired,
    store: HomeAssistantStore = Depends(get_ha_store),
    manager: HomeAssistantManager = Depends(get_ha_manager),
):
    """Get overall HA integration status (for dashboard indicators)."""
    all_sources = store.get_all_sources()
    conn_statuses = manager.get_connection_status()

    # Build a map for quick lookup
    status_map = {s["source_id"]: s for s in conn_statuses}

    connections = []
    connected_count = 0
    for source in all_sources:
        status = status_map.get(source.id)
        connected = status["connected"] if status else False
        if connected:
            connected_count += 1
        connections.append(
            HomeAssistantConnectionStatus(
                source_id=source.id,
                name=source.name,
                connected=connected,
                entity_count=status["entity_count"] if status else 0,
            )
        )

    return HomeAssistantStatusResponse(
        connections=connections,
        total_sources=len(all_sources),
        connected_count=connected_count,
    )
