import sys
import os
import json
import time
import uuid
from pathlib import Path
from datetime import datetime, timezone

from textual.app import App, ComposeResult
from textual.containers import Container, Horizontal, Vertical
from textual.widgets import Header, Footer, Static, ListView, ListItem, Label, Log, DataTable, Input
from textual.reactive import reactive
from textual.binding import Binding

from brynq.server import CHANNELS_DIR, SESSIONS_DIR, _read_jsonl_sync, _append_jsonl_sync

class BrynqTUI(App):
    """A native Terminal User Interface for Brynq Swarms."""

    CSS = """
    Screen {
        layout: vertical;
        background: #0d1117;
    }
    
    #main-container {
        layout: horizontal;
        height: 1fr;
    }
    
    #sidebar {
        width: 30;
        dock: left;
        height: 1fr;
        border-right: vkey #30363d;
        background: #0d1117;
        padding-right: 1;
    }
    
    #messages-pane {
        width: 1fr;
        height: 1fr;
        layout: vertical;
        background: #0d1117;
    }
    
    #agents-pane {
        width: 45;
        dock: right;
        height: 1fr;
        border-left: vkey #30363d;
        background: #0d1117;
        padding-left: 1;
    }
    
    .panel-title {
        color: #8b949e;
        text-align: center;
        text-style: bold;
        padding: 1;
        width: 100%;
        border-bottom: solid #30363d;
    }
    
    #channel-list {
        background: #0d1117;
    }
    
    ListItem {
        padding: 0 1;
        color: #c9d1d9;
    }
    
    ListItem.-active {
        background: #1f6feb;
        color: white;
        text-style: bold;
    }
    
    ListItem.-highlight {
        background: #238636;
        color: white;
    }
    
    #message-log {
        background: #0d1117;
        height: 1fr;
        padding: 0 1;
    }
    
    #input-container {
        height: 3;
        dock: bottom;
        border-top: solid #30363d;
    }
    
    Input {
        width: 100%;
        border: none;
        background: #0d1117;
        color: #c9d1d9;
        padding: 0 1;
    }
    
    Input:focus {
        border: none;
    }
    
    DataTable {
        background: #0d1117;
        color: #c9d1d9;
    }
    
    DataTable > .datatable--header {
        text-style: bold;
        color: #8b949e;
        background: #161b22;
    }
    """

    BINDINGS = [
        Binding("ctrl+q", "quit", "Quit", show=True),
        Binding("ctrl+r", "refresh", "Refresh", show=True),
        Binding("tab", "focus_next", "Focus Next", show=True),
    ]

    current_channel = reactive(None)

    def compose(self) -> ComposeResult:
        yield Header(show_clock=True, icon="🧠 Brynq OS")
        with Horizontal(id="main-container"):
            with Vertical(id="sidebar"):
                yield Label("CHANNELS", classes="panel-title")
                yield ListView(id="channel-list")
            
            with Vertical(id="messages-pane"):
                yield Label("SELECT A CHANNEL", id="messages-title", classes="panel-title")
                yield Log(id="message-log", highlight=True)
                with Container(id="input-container"):
                    yield Input(placeholder="Type a message or /command... (Press Enter to send)", id="chat-input")
            
            with Vertical(id="agents-pane"):
                yield Label("SWARM ACTIVITY", classes="panel-title")
                yield DataTable(id="agents-table")
        yield Footer()

    def on_mount(self) -> None:
        self.title = "Brynq OS - Local Swarm Dashboard"
        self.channels_seen = set()
        self.last_positions = {}
        
        # Setup agents table
        table = self.query_one("#agents-table", DataTable)
        table.add_columns("Agent", "Platform", "Status")
        
        self.refresh_data()
        # Auto-refresh every 500ms
        self.set_interval(0.5, self.refresh_data)
        
        # Focus input by default
        self.query_one("#chat-input", Input).focus()

    def action_refresh(self) -> None:
        self.refresh_data()

    def on_input_submitted(self, event: Input.Submitted) -> None:
        if not self.current_channel:
            return
            
        text = event.value.strip()
        if not text:
            return
            
        event.input.value = ""
        
        entry = {
            "id": uuid.uuid4().hex[:12],
            "timestamp": datetime.now(timezone.utc).isoformat(),
            "session_id": "human-tui",
            "session_name": "TUI-User",
            "platform": "human",
            "channel": self.current_channel,
            "msg_type": "request",
            "message": text,
        }
        
        path = CHANNELS_DIR / f"{self.current_channel}.jsonl"
        _append_jsonl_sync(path, entry)
        self.refresh_data()

    def refresh_data(self) -> None:
        # 1. Update Channels list from file system
        try:
            channel_list = self.query_one("#channel-list", ListView)
        except Exception:
            return # UI not fully mounted
            
        if CHANNELS_DIR.exists():
            for f in sorted(CHANNELS_DIR.glob("*.jsonl")):
                chan = f.stem
                if chan not in self.channels_seen:
                    self.channels_seen.add(chan)
                    safe_id = f"chan-{chan.replace('#', '').replace('_', '-').replace('.', '-').replace(' ', '-')}"
                    
                    try:
                        channel_list.query_one(f"#{safe_id}")
                    except:
                        channel_list.append(ListItem(Label(f"# {chan}"), name=chan, id=safe_id))
                    
                    if self.current_channel is None:
                        self.current_channel = chan
                        channel_list.index = 0

        # 2. Update Messages for current channel
        if self.current_channel:
            path = CHANNELS_DIR / f"{self.current_channel}.jsonl"
            try:
                self.query_one("#messages-title", Label).update(f"#{self.current_channel} Live Feed")
            except Exception:
                pass
                
            if path.exists():
                offset = self.last_positions.get(self.current_channel, 0)
                msgs = _read_jsonl_sync(path, offset=offset)
                if msgs:
                    try:
                        log = self.query_one("#message-log", Log)
                        for m in msgs:
                            ts = m.get("timestamp", "")[11:19]
                            name = m.get("session_name", "?")
                            msg_type = m.get("msg_type", "msg")
                            msg = m.get("message", "")
                            
                            color = "#58a6ff" # default blue
                            if msg_type == "error":
                                color = "#f85149" # red
                            elif msg_type == "task":
                                color = "#d29922" # yellow
                            elif msg_type == "request":
                                color = "#a371f7" # purple
                            elif msg_type == "status":
                                color = "#8b949e" # grey
                            elif m.get("platform") == "human":
                                color = "#3fb950" # green
                                
                            log.write_line(f"[#8b949e]{ts}[/] [[{color} bold]{name}[/]] {msg}")
                            
                        self.last_positions[self.current_channel] = offset + len(msgs)
                    except Exception:
                        pass

        # 3. Update Swarm Agents (Sessions)
        try:
            table = self.query_one("#agents-table", DataTable)
            table.clear()
            if SESSIONS_DIR.exists():
                now = time.time()
                for f in SESSIONS_DIR.glob("*.json"):
                    try:
                        data = json.loads(f.read_text())
                        name = data.get("name", f.stem)
                        plat = data.get("platform", "unknown")
                        hb = data.get("heartbeat")
                        
                        age = 999
                        if hb:
                            try:
                                t1 = datetime.fromisoformat(hb)
                                age = (datetime.now(timezone.utc) - t1).total_seconds()
                            except:
                                pass
                        else:
                            # fallback to file mod time
                            age = now - f.stat().st_mtime
                        
                        if age < 15:
                            status = "[bold #3fb950]● ACTIVE[/]"
                        elif age < 60:
                            status = "[bold #d29922]● IDLE[/]"
                        else:
                            status = "[bold #f85149]○ DEAD[/]"
                            
                        table.add_row(name, plat, status)
                    except Exception:
                        pass
        except Exception:
            pass

    def on_list_view_selected(self, event: ListView.Selected) -> None:
        self.current_channel = event.item.name
        try:
            self.query_one("#message-log", Log).clear()
        except Exception:
            pass
        self.last_positions[self.current_channel] = 0
        self.refresh_data()

def main():
    app = BrynqTUI()
    app.run()

if __name__ == "__main__":
    main()
