from __future__ import annotations

import asyncio
import json
import logging
import os
import shutil
import subprocess
import sys
import threading
import time
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple

from textual.app import App, ComposeResult
from textual.binding import Binding
from textual.containers import Horizontal, Vertical, VerticalScroll, Container
from textual.widgets import Footer, Header, Input, Label, Static, ListItem, ListView
from textual.worker import Worker, WorkerState
from textual.reactive import reactive

from runtime.config import RuntimeConfig, load_config
from runtime.rooms.room_manager import room_manager
from runtime.rooms.profile import local_profile
from runtime.rooms.project_store import ProjectStore
from runtime.executor.pipeline.model_router import call_model
from runtime.security.trust import TrustManager, TrustLevel
from runtime.security.moderation import ModerationManager
from runtime.security.permissions import PermissionManager
from runtime.security.docker_sandbox import docker_available

# --- Cyberpunk Dark Theme ---
BRYNQ_CSS = """
Screen {
    background: #0a0a14;
    color: #c0c0d0;
    font-family: "JetBrains Mono", "Courier New", monospace;
}

#body {
    layout: horizontal;
    height: 1fr;
}

/* --- Sidebar Panels --- */
.sidebar {
    width: 30;
    background: #0f1020;
    border-right: solid #1a1a3a;
}

.sidebar-right {
    width: 26;
    background: #0f1020;
    border-left: solid #1a1a3a;
}

.panel-header {
    background: #1a1a3a;
    color: #00d4aa;
    text-style: bold;
    text-align: left;
    width: 100%;
    height: 1;
    padding: 0 1;
    margin-bottom: 1;
}

/* --- People & Room List --- */
.list-item {
    padding: 0 1;
    height: 1;
    color: #8888aa;
}

.list-item:hover {
    background: #1a2a4a;
    color: #e0e0e0;
}

.active-item {
    background: #1a2a4a;
    color: #e0e0e0;
    text-style: bold;
}

.online-dot { color: #00d4aa; }
.offline-dot { color: #333355; }

/* --- Chat Feed --- */
#center-panel {
    width: 1fr;
    background: #0a0a14;
}

#chat-feed {
    height: 1fr;
    overflow-y: auto;
    padding: 1 2;
}

.message {
    margin-bottom: 1;
}

.msg-sender {
    text-style: bold;
    color: #4a9eff;
}

.msg-content {
    color: #c0c0d0;
}

.msg-ai-tag {
    color: #4a9eff;
    text-style: italic;
}

.msg-system {
    color: #666688;
    text-align: center;
    italic: True;
}

/* --- Input Bar --- */
#input-container {
    height: 3;
    background: #0c0c1a;
    border-top: solid #2a2a5a;
    padding: 0 1;
}

#chat-input {
    width: 100%;
    background: #0a0a14;
    color: #c0c0d0;
    border: none;
}

#chat-input:focus {
    border: solid #4a4aff;
}

/* --- Status Indicators --- */
.status-thinking { color: #ffcc00; }
.status-error { color: #ff4444; }
.status-success { color: #00d4aa; }
"""

class PeoplePanel(ListView):
    """Left sidebar: Online friends and teammates."""
    def refresh_people(self, users: List[Dict[str, Any]], current_user_id: str):
        self.clear()
        for user in users:
            if user["user_id"] == current_user_id:
                name = f"{user['username']} (you)"
            else:
                name = user["username"]
            
            status = user.get("status", "online")
            model_count = len(user.get("models", []))
            self.append(PeopleListItem(name, status, model_count))

class RoomList(ListView):
    """Left sidebar: Your active rooms."""
    def refresh_rooms(self, rooms: List[Dict[str, Any]], active_id: Optional[str]):
        self.clear()
        for room in rooms:
            is_active = room.get("room_id") == active_id
            self.append(RoomListItem(room["name"], room["room_code"], active=is_active))

class ProjectFiles(ListView):
    """Left sidebar: Active project file tree."""
    def refresh_files(self, files: List[Dict[str, Any]]):
        self.clear()
        for f in files:
            self.append(ListItem(Label(f"  {f['relative_path']}")))

class BrynqSocialTUI(App):
    TITLE = "BRYNQ SOCIAL"
    CSS = BRYNQ_CSS
    
    BINDINGS = [
        Binding("ctrl+q", "quit", "Quit"),
        Binding("ctrl+n", "new_room", "New Room"),
        Binding("ctrl+j", "join_room", "Join Room"),
        Binding("tab", "cycle_focus", "Focus"),
        Binding("ctrl+l", "clear_chat", "Clear"),
        Binding("ctrl+p", "toggle_projects", "Project Panel"),
    ]

    active_room_id = reactive(None)

    def compose(self) -> ComposeResult:
        yield Header()
        with Horizontal(id="body"):
            with Vertical(classes="sidebar"):
                yield Label("PEOPLE", classes="panel-header")
                yield PeoplePanel(id="people-list")
                yield Label("ROOMS", classes="panel-header")
                yield RoomList(id="room-list")
                yield Label("PROJECTS", classes="panel-header")
                yield ProjectFiles(id="project-list")
            with Vertical(id="center-panel"):
                yield VerticalScroll(id="chat-feed")
                with Container(id="input-container"):
                    yield Input(placeholder="Type to chat, @mention to invoke AI...", id="chat-input")
            with Vertical(classes="sidebar-right"):
                yield Label("ROOM INFO", classes="panel-header")
                yield Static("No active room", id="room-info")
                yield Label("MODELS", classes="panel-header")
                yield VerticalScroll(id="model-status")
                yield Label("PROJECT", classes="panel-header")
                yield Static("No active project", id="project-info")
        yield Footer()

    async def on_mount(self) -> None:
        self.query_one("#chat-input", Input).focus()
        self._add_system_message("Connected to Brynq Social network.")

        # Load profile
        prof = local_profile.get()
        self.username = prof.get("username", "User")
        self.user_id = prof.get("user_id", "abc")

        # Security managers
        self._trust = TrustManager(owner_id=self.user_id)
        self._moderation = ModerationManager()
        self._permissions = PermissionManager()

        # Start loops
        self.run_worker(self._refresh_loop)
        self.run_worker(self._heartbeat_loop)

    async def _refresh_loop(self):
        while True:
            try:
                # People
                online = await room_manager.get_online_users()
                self.query_one("#people-list", PeoplePanel).refresh_people(online, self.user_id)
                
                # Rooms
                if self.user_id:
                    # In a real app we'd fetch all user rooms
                    pass
                
                # Projects
                store = self._get_active_store()
                if store:
                    files = store.list_files()
                    self.query_one("#project-list", ProjectFiles).refresh_files(files)
                    self.query_one("#project-info", Static).update(f"Files: {len(files)}")
                
                # Room Info
                if room_manager.active_room:
                    r = room_manager.active_room
                    self.query_one("#room-info", Static).update(f"#{r['name']}\nCode: {r['room_code']}")
                
            except Exception:
                pass
            await asyncio.sleep(5)

    def _get_active_store(self) -> Optional[ProjectStore]:
        if room_manager.is_host and room_manager.host_service:
            return getattr(room_manager.host_service, 'project_store', None)
        elif room_manager.client_service:
            return getattr(room_manager.client_service, 'project_store', None)
        return None

    def on_input_submitted(self, event: Input.Submitted) -> None:
        text = event.value.strip()
        if not text: return
        event.input.value = ""

        # Slash commands for security
        if text.startswith("/"):
            self._handle_slash_command(text)
            return

        # Intent Detection (simplified for TUI)
        if text.startswith("@brynq") or text.startswith("@ai"):
            prompt = text[7:].strip() if text.startswith("@brynq") else text[4:].strip()
            self._add_chat_message(self.username, text)
            self.run_worker(lambda: self._call_ai(prompt), thread=True)
        else:
            self._add_chat_message(self.username, text)
            if room_manager.active_room:
                room_manager.send_message(text)

    def _handle_slash_command(self, text: str) -> None:
        """Route /slash commands for security features."""
        parts = text.split()
        cmd = parts[0].lower()

        if cmd == "/trust":
            # /trust <username> <level>
            if len(parts) < 3:
                self._add_system_message("Usage: /trust <username> <level>")
                self._add_system_message("Levels: STRANGER, ROOM_MEMBER, FRIEND, OWNER")
                return
            username = parts[1]
            level_name = parts[2].upper()
            try:
                level = TrustLevel[level_name]
            except KeyError:
                self._add_system_message(f"Unknown trust level: {level_name}")
                self._add_system_message("Valid levels: STRANGER, ROOM_MEMBER, FRIEND, OWNER")
                return
            self._trust.set_trust_level(username, level)
            self._add_system_message(f"Trust for {username} set to {level_name}")

        elif cmd == "/block":
            if len(parts) < 2:
                self._add_system_message("Usage: /block <username> [reason]")
                return
            username = parts[1]
            reason = " ".join(parts[2:]) if len(parts) > 2 else ""
            self._moderation.block_user(username, reason)
            self._add_system_message(f"Blocked {username}")

        elif cmd == "/unblock":
            if len(parts) < 2:
                self._add_system_message("Usage: /unblock <username>")
                return
            username = parts[1]
            self._moderation.unblock_user(username)
            self._add_system_message(f"Unblocked {username}")

        elif cmd == "/permissions":
            grants = self._permissions.list_grants()
            if not grants:
                self._add_system_message("No permission grants active.")
            else:
                for peer_id, actions in grants.items():
                    self._add_system_message(f"  {peer_id}: {', '.join(actions)}")

        elif cmd == "/security":
            docker_ok = docker_available()
            keys_dir = Path.home() / ".brynq" / "keys"
            keys_exist = (keys_dir / "ed25519.key").exists()
            blocked_count = len(self._moderation.list_blocked())
            trust_overrides = len(self._trust.list_overrides())
            perm_grants = sum(len(v) for v in self._permissions.list_grants().values())

            self._add_system_message("--- Security Status ---")
            self._add_system_message(f"  Docker sandbox: {'available' if docker_ok else 'NOT available'}")
            self._add_system_message(f"  Signing keys:   {'generated' if keys_exist else 'not generated'}")
            self._add_system_message(f"  Blocked users:  {blocked_count}")
            self._add_system_message(f"  Trust overrides: {trust_overrides}")
            self._add_system_message(f"  Perm grants:    {perm_grants}")

        elif cmd == "/report":
            if len(parts) < 3:
                self._add_system_message("Usage: /report <username> <reason>")
                return
            username = parts[1]
            reason = " ".join(parts[2:])
            result = self._moderation.report_user(username, reason, reporter_id=self.user_id)
            self._add_system_message(f"Report submitted: {result.get('status', 'unknown')}")

        else:
            self._add_system_message(f"Unknown command: {cmd}")
            self._add_system_message("Available: /trust /block /unblock /permissions /security /report")

    def _call_ai(self, prompt: str):
        # Determine strategy from prompt
        strategy = "single"
        if "debate" in prompt.lower(): strategy = "debate"
        elif "refine" in prompt.lower(): strategy = "refine"
        
        # Real call via model_router
        model = "claude" # default
        response = call_model(model, prompt)
        self.call_from_thread(self._add_chat_message, f"[{model.upper()}]", response, "ai")

    def _add_system_message(self, text: str):
        feed = self.query_one("#chat-feed", VerticalScroll)
        feed.mount(Label(f"--- {text} ---", classes="msg-system"))
        feed.scroll_to_bottom()

    def _add_chat_message(self, sender: str, content: str, msg_type: str = "human"):
        feed = self.query_one("#chat-feed", VerticalScroll)
        msg = ChatMessage(sender, content, msg_type)
        feed.mount(msg)
        feed.scroll_to_bottom()

    async def _heartbeat_loop(self):
        while True:
            try:
                await room_manager.send_heartbeat(status="online")
            except Exception:
                pass
            await asyncio.sleep(30)

    def action_cycle_focus(self) -> None:
        nodes = [self.query_one("#people-list"), self.query_one("#room-list"), 
                 self.query_one("#project-list"), self.query_one("#chat-input")]
        try:
            curr_idx = nodes.index(self.focused)
            nodes[(curr_idx + 1) % len(nodes)].focus()
        except ValueError:
            nodes[0].focus()

    def action_new_room(self) -> None:
        self._add_system_message("Creating room...")
        self.run_worker(self._create_room_task)

    async def _create_room_task(self):
        try:
            room = await room_manager.create_room("Workspace")
            self._add_system_message(f"Room Created: {room['room_code']}")
        except Exception as e:
            self._add_system_message(f"Error: {e}")

    def action_join_room(self) -> None:
        # For simplicity in TUI without popup, we could use a special input mode
        self._add_system_message("Use /room join <code> in chat to join.")

    def action_toggle_projects(self) -> None:
        pl = self.query_one("#project-list")
        pl.display = not pl.display

if __name__ == "__main__":
    app = BrynqSocialTUI()
    app.run()
