from fastapi import APIRouter, HTTPException

from app.dependencies import require_connected
from app.models import (
    CONTACT_TYPE_ROOM,
    AclEntry,
    LppSensor,
    RepeaterAclResponse,
    RepeaterLoginRequest,
    RepeaterLoginResponse,
    RepeaterLppTelemetryResponse,
    RepeaterStatusResponse,
)
from app.routers.contacts import _ensure_on_radio, _resolve_contact_or_404
from app.routers.server_control import (
    prepare_authenticated_contact_connection,
    require_server_capable_contact,
)
from app.services.radio_runtime import radio_runtime as radio_manager

router = APIRouter(prefix="/contacts", tags=["rooms"])


def _require_room(contact) -> None:
    require_server_capable_contact(contact, allowed_types=(CONTACT_TYPE_ROOM,))


@router.post("/{public_key}/room/login", response_model=RepeaterLoginResponse)
async def room_login(public_key: str, request: RepeaterLoginRequest) -> RepeaterLoginResponse:
    """Attempt room-server login and report whether auth was confirmed."""
    require_connected()
    contact = await _resolve_contact_or_404(public_key)
    _require_room(contact)

    async with radio_manager.radio_operation(
        "room_login",
        pause_polling=True,
        suspend_auto_fetch=True,
    ) as mc:
        return await prepare_authenticated_contact_connection(
            mc,
            contact,
            request.password,
            label="room server",
        )


@router.post("/{public_key}/room/status", response_model=RepeaterStatusResponse)
async def room_status(public_key: str) -> RepeaterStatusResponse:
    """Fetch status telemetry from a room server."""
    require_connected()
    contact = await _resolve_contact_or_404(public_key)
    _require_room(contact)

    async with radio_manager.radio_operation(
        "room_status", pause_polling=True, suspend_auto_fetch=True
    ) as mc:
        await _ensure_on_radio(mc, contact)
        status = await mc.commands.req_status_sync(contact.public_key, timeout=10, min_timeout=5)

    if status is None:
        raise HTTPException(status_code=504, detail="No status response from room server")

    return RepeaterStatusResponse(
        battery_volts=status.get("bat", 0) / 1000.0,
        tx_queue_len=status.get("tx_queue_len", 0),
        noise_floor_dbm=status.get("noise_floor", 0),
        last_rssi_dbm=status.get("last_rssi", 0),
        last_snr_db=status.get("last_snr", 0.0),
        packets_received=status.get("nb_recv", 0),
        packets_sent=status.get("nb_sent", 0),
        airtime_seconds=status.get("airtime", 0),
        rx_airtime_seconds=status.get("rx_airtime", 0),
        uptime_seconds=status.get("uptime", 0),
        sent_flood=status.get("sent_flood", 0),
        sent_direct=status.get("sent_direct", 0),
        recv_flood=status.get("recv_flood", 0),
        recv_direct=status.get("recv_direct", 0),
        flood_dups=status.get("flood_dups", 0),
        direct_dups=status.get("direct_dups", 0),
        full_events=status.get("full_evts", 0),
    )


@router.post("/{public_key}/room/lpp-telemetry", response_model=RepeaterLppTelemetryResponse)
async def room_lpp_telemetry(public_key: str) -> RepeaterLppTelemetryResponse:
    """Fetch CayenneLPP telemetry from a room server."""
    require_connected()
    contact = await _resolve_contact_or_404(public_key)
    _require_room(contact)

    async with radio_manager.radio_operation(
        "room_lpp_telemetry", pause_polling=True, suspend_auto_fetch=True
    ) as mc:
        await _ensure_on_radio(mc, contact)
        telemetry = await mc.commands.req_telemetry_sync(
            contact.public_key, timeout=10, min_timeout=5
        )

    if telemetry is None:
        raise HTTPException(status_code=504, detail="No telemetry response from room server")

    sensors = [
        LppSensor(
            channel=entry.get("channel", 0),
            type_name=str(entry.get("type", "unknown")),
            value=entry.get("value", 0),
        )
        for entry in telemetry
    ]
    return RepeaterLppTelemetryResponse(sensors=sensors)


@router.post("/{public_key}/room/acl", response_model=RepeaterAclResponse)
async def room_acl(public_key: str) -> RepeaterAclResponse:
    """Fetch ACL entries from a room server."""
    require_connected()
    contact = await _resolve_contact_or_404(public_key)
    _require_room(contact)

    async with radio_manager.radio_operation(
        "room_acl", pause_polling=True, suspend_auto_fetch=True
    ) as mc:
        await _ensure_on_radio(mc, contact)
        acl_data = await mc.commands.req_acl_sync(contact.public_key, timeout=10, min_timeout=5)

    acl_entries = []
    if acl_data and isinstance(acl_data, list):
        from app.repository import ContactRepository
        from app.routers.repeaters import ACL_PERMISSION_NAMES

        for entry in acl_data:
            pubkey_prefix = entry.get("key", "")
            perm = entry.get("perm", 0)
            resolved_contact = await ContactRepository.get_by_key_prefix(pubkey_prefix)
            acl_entries.append(
                AclEntry(
                    pubkey_prefix=pubkey_prefix,
                    name=resolved_contact.name if resolved_contact else None,
                    permission=perm,
                    permission_name=ACL_PERMISSION_NAMES.get(perm, f"Unknown({perm})"),
                )
            )

    return RepeaterAclResponse(acl=acl_entries)
