import logging
import database as db

logger = logging.getLogger("mqtt.logger")

LEVEL_MAP = {
    "🟢 INFO": "INFO",
    "🟡 WARN": "WARN",
    "🔴 EROR": "ERROR",
    "INFO": "INFO",
    "WARN": "WARN",
    "ERROR": "ERROR",
    "EROR": "ERROR",
}


async def handle_message(serial: str, topic_type: str, payload: dict):
    try:
        if topic_type == "status/heartbeat":
            await _handle_heartbeat(serial, payload)
        elif topic_type == "status/alerts":
            await _handle_alerts(serial, payload)
        elif topic_type == "status/info":
            await _handle_info(serial, payload)
        elif topic_type == "logs":
            await _handle_log(serial, payload)
        elif topic_type == "data":
            await _handle_data_response(serial, payload)
        else:
            logger.debug(f"Unhandled topic type: {topic_type} for {serial}")
    except Exception as e:
        logger.error(f"Error handling {topic_type} for {serial}: {e}")


async def _handle_heartbeat(serial: str, payload: dict):
    # Store silently — do not log as a visible event.
    # The console surfaces an alert only when the device goes silent (no heartbeat for 90s).
    inner = payload.get("payload", {})
    await db.insert_heartbeat(
        device_serial=serial,
        device_id=inner.get("device_id", ""),
        firmware_version=inner.get("firmware_version", ""),
        ip_address=inner.get("ip_address", ""),
        gateway=inner.get("gateway", ""),
        uptime_ms=inner.get("uptime_ms", 0),
        uptime_display=inner.get("timestamp", ""),
    )


async def _handle_log(serial: str, payload: dict):
    raw_level = payload.get("level", "INFO")
    level = LEVEL_MAP.get(raw_level, "INFO")
    message = payload.get("message", "")
    device_timestamp = payload.get("timestamp")

    await db.insert_log(
        device_serial=serial,
        level=level,
        message=message,
        device_timestamp=device_timestamp,
    )


async def _handle_alerts(serial: str, payload: dict):
    subsystem = payload.get("subsystem", "")
    state = payload.get("state", "")
    if not subsystem or not state:
        logger.warning(f"Malformed alert payload from {serial}: {payload}")
        return

    if state == "CLEARED":
        await db.delete_alert(serial, subsystem)
    else:
        await db.upsert_alert(serial, subsystem, state, payload.get("msg"))


async def _handle_info(serial: str, payload: dict):
    event_type = payload.get("type", "")
    data = payload.get("payload", {})

    if event_type == "playback_started":
        logger.debug(f"{serial}: playback started — melody_uid={data.get('melody_uid')}")
    elif event_type == "playback_stopped":
        logger.debug(f"{serial}: playback stopped")
    else:
        logger.debug(f"{serial}: info event '{event_type}'")


async def _handle_data_response(serial: str, payload: dict):
    status = payload.get("status", "")

    pending = await db.get_pending_command(serial)
    if pending:
        cmd_status = "success" if status == "SUCCESS" else "error"
        await db.update_command_response(
            command_id=pending["id"],
            status=cmd_status,
            response_payload=payload,
        )
    else:
        logger.debug(f"Received data response for {serial} with no pending command")
