"""MQTT source routes: CRUD + test + status."""

import asyncio

import aiomqtt
from fastapi import APIRouter, Depends, HTTPException

from wled_controller.api.auth import AuthRequired
from wled_controller.api.dependencies import (
    fire_entity_event,
    get_mqtt_manager,
    get_mqtt_store,
)
from wled_controller.api.schemas.mqtt import (
    MQTTConnectionStatus,
    MQTTSourceCreate,
    MQTTSourceListResponse,
    MQTTSourceResponse,
    MQTTSourceUpdate,
    MQTTStatusResponse,
    MQTTTestResponse,
)
from wled_controller.core.mqtt.mqtt_manager import MQTTManager
from wled_controller.storage.base_store import EntityNotFoundError
from wled_controller.storage.mqtt_source import MQTTSource
from wled_controller.storage.mqtt_source_store import MQTTSourceStore
from wled_controller.utils import get_logger

logger = get_logger(__name__)

router = APIRouter()


def _to_response(source: MQTTSource, manager: MQTTManager) -> MQTTSourceResponse:
    runtime = manager.get_runtime(source.id)
    return MQTTSourceResponse(
        id=source.id,
        name=source.name,
        broker_host=source.broker_host,
        broker_port=source.broker_port,
        username=source.username,
        password_set=bool(source.password),
        client_id=source.client_id,
        base_topic=source.base_topic,
        connected=runtime.is_connected if runtime else False,
        description=source.description,
        tags=source.tags,
        created_at=source.created_at,
        updated_at=source.updated_at,
    )


@router.get(
    "/api/v1/mqtt/sources",
    response_model=MQTTSourceListResponse,
    tags=["MQTT"],
)
async def list_mqtt_sources(
    _auth: AuthRequired,
    store: MQTTSourceStore = Depends(get_mqtt_store),
    manager: MQTTManager = Depends(get_mqtt_manager),
):
    sources = store.get_all_sources()
    return MQTTSourceListResponse(
        sources=[_to_response(s, manager) for s in sources],
        count=len(sources),
    )


@router.post(
    "/api/v1/mqtt/sources",
    response_model=MQTTSourceResponse,
    status_code=201,
    tags=["MQTT"],
)
async def create_mqtt_source(
    data: MQTTSourceCreate,
    _auth: AuthRequired,
    store: MQTTSourceStore = Depends(get_mqtt_store),
    manager: MQTTManager = Depends(get_mqtt_manager),
):
    try:
        source = store.create_source(
            name=data.name,
            broker_host=data.broker_host,
            broker_port=data.broker_port,
            username=data.username,
            password=data.password,
            client_id=data.client_id,
            base_topic=data.base_topic,
            description=data.description,
            tags=data.tags,
        )
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    fire_entity_event("mqtt_source", "created", source.id)
    return _to_response(source, manager)


@router.get(
    "/api/v1/mqtt/sources/{source_id}",
    response_model=MQTTSourceResponse,
    tags=["MQTT"],
)
async def get_mqtt_source(
    source_id: str,
    _auth: AuthRequired,
    store: MQTTSourceStore = Depends(get_mqtt_store),
    manager: MQTTManager = Depends(get_mqtt_manager),
):
    try:
        source = store.get_source(source_id)
    except EntityNotFoundError:
        raise HTTPException(status_code=404, detail=f"MQTT source {source_id} not found")
    return _to_response(source, manager)


@router.put(
    "/api/v1/mqtt/sources/{source_id}",
    response_model=MQTTSourceResponse,
    tags=["MQTT"],
)
async def update_mqtt_source(
    source_id: str,
    data: MQTTSourceUpdate,
    _auth: AuthRequired,
    store: MQTTSourceStore = Depends(get_mqtt_store),
    manager: MQTTManager = Depends(get_mqtt_manager),
):
    try:
        source = store.update_source(
            source_id,
            name=data.name,
            broker_host=data.broker_host,
            broker_port=data.broker_port,
            username=data.username,
            password=data.password,
            client_id=data.client_id,
            base_topic=data.base_topic,
            description=data.description,
            tags=data.tags,
        )
    except EntityNotFoundError:
        raise HTTPException(status_code=404, detail=f"MQTT 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("mqtt_source", "updated", source.id)
    return _to_response(source, manager)


@router.delete("/api/v1/mqtt/sources/{source_id}", status_code=204, tags=["MQTT"])
async def delete_mqtt_source(
    source_id: str,
    _auth: AuthRequired,
    store: MQTTSourceStore = Depends(get_mqtt_store),
    manager: MQTTManager = Depends(get_mqtt_manager),
):
    try:
        store.delete_source(source_id)
    except EntityNotFoundError:
        raise HTTPException(status_code=404, detail=f"MQTT source {source_id} not found")
    # Release any active runtime
    await manager.release(source_id)
    fire_entity_event("mqtt_source", "deleted", source_id)


@router.post(
    "/api/v1/mqtt/sources/{source_id}/test",
    response_model=MQTTTestResponse,
    tags=["MQTT"],
)
async def test_mqtt_source(
    source_id: str,
    _auth: AuthRequired,
    store: MQTTSourceStore = Depends(get_mqtt_store),
):
    """Test connection to an MQTT broker."""
    try:
        source = store.get_source(source_id)
    except EntityNotFoundError:
        raise HTTPException(status_code=404, detail=f"MQTT source {source_id} not found")

    try:
        async with aiomqtt.Client(
            hostname=source.broker_host,
            port=source.broker_port,
            username=source.username or None,
            password=source.password or None,
            identifier=f"{source.client_id}-test",
            timeout=10.0,
        ):
            return MQTTTestResponse(success=True)
    except asyncio.TimeoutError:
        return MQTTTestResponse(success=False, error="Connection timed out")
    except Exception as e:
        return MQTTTestResponse(success=False, error=str(e))


@router.get(
    "/api/v1/mqtt/status",
    response_model=MQTTStatusResponse,
    tags=["MQTT"],
)
async def get_mqtt_status(
    _auth: AuthRequired,
    store: MQTTSourceStore = Depends(get_mqtt_store),
    manager: MQTTManager = Depends(get_mqtt_manager),
):
    """Get overall MQTT integration status (for dashboard indicators)."""
    all_sources = store.get_all_sources()
    statuses = manager.get_all_sources_status()
    status_map = {s["source_id"]: s for s in 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(
            MQTTConnectionStatus(
                source_id=source.id,
                name=source.name,
                connected=connected,
                broker=f"{source.broker_host}:{source.broker_port}",
            )
        )

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