"""Rational UI — PyScript application running in the browser.

This Python code executes inside Pyodide (WebAssembly). It manages:
- WebSocket connection to the backend
- Real-time message routing to UI panels (chat, logs, agents)
- DOM manipulation via pyscript.web / pyscript.document
- User input handling

No build step required — edit this file and refresh the browser.
"""

import json
from datetime import datetime

from pyscript import document, WebSocket, when, window


# ---------------------------------------------------------------------------
# State
# ---------------------------------------------------------------------------
class AppState:
    ws = None
    connection_id = None
    connected = False
    active_panel = "chat"


state = AppState()


# ---------------------------------------------------------------------------
# DOM helpers
# ---------------------------------------------------------------------------
def qs(selector):
    return document.querySelector(selector)


def set_status(connected: bool, text: str = ""):
    dot = qs("#ws-status-dot")
    label = qs("#ws-status-text")
    if connected:
        dot.classList.add("connected")
        label.textContent = text or "Connected"
    else:
        dot.classList.remove("connected")
        label.textContent = text or "Disconnected"


def timestamp():
    return datetime.now().strftime("%H:%M:%S")


# ---------------------------------------------------------------------------
# Chat
# ---------------------------------------------------------------------------
def append_chat(text: str, sent: bool = False, meta: str = ""):
    container = qs("#chat-messages")
    # Clear empty state
    empty = container.querySelector(".empty-state")
    if empty:
        empty.remove()

    div = document.createElement("div")
    div.classList.add("msg")
    div.classList.add("sent" if sent else "received")
    div.textContent = text

    if meta:
        meta_el = document.createElement("div")
        meta_el.classList.add("meta")
        meta_el.textContent = meta
        div.appendChild(meta_el)

    container.appendChild(div)
    container.scrollTop = container.scrollHeight


# ---------------------------------------------------------------------------
# Logs
# ---------------------------------------------------------------------------
def append_log(level: str, message: str, ts: str = ""):
    container = qs("#log-container")
    empty = container.querySelector(".empty-state")
    if empty:
        empty.remove()

    div = document.createElement("div")
    div.classList.add("log-entry")

    ts_text = ts or timestamp()
    level_class = f"level-{level.lower()}"
    div.innerHTML = (
        f'<span class="ts">{ts_text}</span> '
        f'<span class="{level_class}">[{level.upper()}]</span> '
        f'{message}'
    )
    container.appendChild(div)
    container.scrollTop = container.scrollHeight


# ---------------------------------------------------------------------------
# Agents
# ---------------------------------------------------------------------------
def update_agent(agent_id: str, name: str, agent_state: str, detail: str = ""):
    container = qs("#agent-container")
    empty = container.querySelector(".empty-state")
    if empty:
        empty.remove()

    card_id = f"agent-{agent_id}"
    card = document.getElementById(card_id)
    if not card:
        card = document.createElement("div")
        card.classList.add("agent-card")
        card.id = card_id
        container.appendChild(card)

    badge_class = "running" if agent_state == "running" else ("error" if agent_state == "error" else "idle")
    card.innerHTML = (
        f'<div class="name">{name}</div>'
        f'<div class="state"><span class="badge {badge_class}">{agent_state}</span>'
        f'{" — " + detail if detail else ""}</div>'
    )


# ---------------------------------------------------------------------------
# WebSocket
# ---------------------------------------------------------------------------
def ws_connect():
    protocol = "wss" if window.location.protocol == "https:" else "ws"
    host = window.location.host
    url = f"{protocol}://{host}/ws?tenant_id=ui-default"

    ws = WebSocket(url=url)

    def on_open(event):
        state.ws = ws
        state.connected = True
        set_status(True)
        # Subscribe to all topics
        for topic in ("chat", "logs", "agent-status"):
            ws.send(json.dumps({"type": "subscribe", "topic": topic}))
        append_log("info", "WebSocket connected")

    def on_message(event):
        try:
            msg = json.loads(event.data)
        except Exception:
            return

        msg_type = msg.get("type", "")
        topic = msg.get("topic", "")
        payload = msg.get("payload", {})

        if msg_type == "connected":
            state.connection_id = payload.get("connection_id", "")
            return

        if msg_type == "ack":
            return

        if msg_type == "error":
            append_log("error", payload.get("detail", "unknown error"))
            return

        # Route by topic
        if topic == "chat":
            sender = payload.get("from", "?")
            text = payload.get("text", "")
            is_self = sender == state.connection_id
            if not is_self:
                append_chat(text, sent=False, meta=f"from {sender[:8]}...")

        elif topic == "logs":
            append_log(
                payload.get("level", "info"),
                payload.get("msg", str(payload)),
                payload.get("ts", ""),
            )

        elif topic == "agent-status":
            update_agent(
                payload.get("agent_id", "?"),
                payload.get("name", "Agent"),
                payload.get("state", "idle"),
                payload.get("detail", ""),
            )

    def on_close(event):
        state.ws = None
        state.connected = False
        set_status(False)
        append_log("warn", "WebSocket disconnected")

    def on_error(event):
        state.connected = False
        set_status(False, "Error")
        append_log("error", "WebSocket error")

    ws.onopen = on_open
    ws.onmessage = on_message
    ws.onclose = on_close
    ws.onerror = on_error


# ---------------------------------------------------------------------------
# Navigation
# ---------------------------------------------------------------------------
def switch_panel(panel_name):
    state.active_panel = panel_name
    for btn in document.querySelectorAll(".sidebar button"):
        btn.classList.remove("active")
    for panel in document.querySelectorAll(".panel"):
        panel.classList.remove("active")

    btn = document.querySelector(f'[data-panel="{panel_name}"]')
    if btn:
        btn.classList.add("active")
    panel = document.getElementById(f"panel-{panel_name}")
    if panel:
        panel.classList.add("active")


@when("click", "#nav-chat")
def on_nav_chat(event):
    switch_panel("chat")


@when("click", "#nav-logs")
def on_nav_logs(event):
    switch_panel("logs")


@when("click", "#nav-agents")
def on_nav_agents(event):
    switch_panel("agents")


# ---------------------------------------------------------------------------
# Chat input
# ---------------------------------------------------------------------------
def send_chat():
    inp = qs("#chat-input")
    text = inp.value.strip()
    if not text or not state.ws:
        return
    state.ws.send(json.dumps({
        "type": "message",
        "topic": "chat",
        "payload": {"text": text},
    }))
    append_chat(text, sent=True, meta=timestamp())
    inp.value = ""


@when("click", "#chat-send")
def on_chat_send(event):
    send_chat()


@when("keydown", "#chat-input")
def on_chat_keydown(event):
    if event.key == "Enter":
        send_chat()


# ---------------------------------------------------------------------------
# Version display
# ---------------------------------------------------------------------------
async def fetch_version():
    """Fetch version info from the backend and display in header badge."""
    try:
        from pyodide.http import pyfetch
        resp = await pyfetch("/api/ui/version")
        if resp.ok:
            data = await resp.json()
            version = data.get("version", "?")
            sha = data.get("git_sha", "?")
            badge = qs("#version-badge")
            if badge:
                badge.textContent = f"v{version}+{sha}"
    except Exception:
        pass  # Non-critical — badge stays empty


# ---------------------------------------------------------------------------
# Boot
# ---------------------------------------------------------------------------
set_status(False, "Connecting...")
ws_connect()
# Fire-and-forget version fetch (async in PyScript)
from pyscript import when as _when  # noqa: E402
import asyncio as _asyncio  # noqa: E402
_asyncio.ensure_future(fetch_version())
