"""
TUI Dashboard - Terminal User Interface for Agent Orchestrator.

Provides:
- Real-time agent status monitoring
- Task queue visualization
- Cost tracking display
- Interactive controls

Inspired by Claude Squad and Textual framework.
"""

import asyncio
import logging
from datetime import datetime
from typing import Any, Callable, Optional

from textual.app import App, ComposeResult
from textual.binding import Binding
from textual.containers import Container, Horizontal, Vertical, ScrollableContainer
from textual.widgets import (
    Header,
    Footer,
    Static,
    DataTable,
    ProgressBar,
    Label,
    Button,
    Input,
    RichLog,
)
from textual.reactive import reactive
from textual.timer import Timer
from rich.panel import Panel
from rich.table import Table
from rich.text import Text

from .widgets.agent_status import AgentStatusPanel
from .widgets.task_queue import TaskQueuePanel
from .widgets.active_task import ActiveTaskPanel
from .widgets.cost_summary import CostSummaryBar

logger = logging.getLogger(__name__)


class OrchestratorDashboard(App):
    """
    Main TUI dashboard for Agent Orchestrator.

    Features:
    - Real-time agent status with rate limit progress bars
    - Task queue with pending/running tasks
    - Active task details with live output
    - Cost tracking and budget alerts
    - Vim-style keyboard navigation

    Example:
        dashboard = OrchestratorDashboard()
        dashboard.run()
    """

    CSS = """
    /* Layout */
    #main-container {
        layout: grid;
        grid-size: 2;
        grid-columns: 1fr 2fr;
        height: 100%;
    }

    #left-panel {
        height: 100%;
        border: solid $primary;
    }

    #right-panel {
        height: 100%;
    }

    #agents-panel {
        height: 60%;
        border: solid $success;
        padding: 1;
    }

    #task-queue-panel {
        height: 40%;
        border: solid $warning;
        padding: 1;
    }

    #active-task-panel {
        height: 70%;
        border: solid $primary;
        padding: 1;
    }

    #log-panel {
        height: 30%;
        border: solid $secondary;
        padding: 1;
    }

    /* Widgets */
    .panel-title {
        text-style: bold;
        color: $text;
        margin-bottom: 1;
    }

    .agent-row {
        height: 3;
        margin: 1 0;
    }

    .status-emoji {
        width: 3;
    }

    .agent-name {
        width: 15;
    }

    .usage-bar {
        width: 20;
    }

    .usage-percent {
        width: 8;
    }

    /* Cost bar */
    #cost-bar {
        dock: bottom;
        height: 3;
        background: $surface;
        padding: 0 2;
    }

    /* Alerts */
    .alert-warning {
        background: $warning;
        color: $text;
    }

    .alert-critical {
        background: $error;
        color: $text;
    }

    /* Selection */
    .selected {
        background: $accent;
    }

    /* Buttons */
    Button {
        margin: 1;
    }
    """

    BINDINGS = [
        Binding("q", "quit", "Quit", show=True),
        Binding("?", "help", "Help", show=True),
        Binding("n", "new_task", "New Task", show=True),
        Binding("p", "pause_agent", "Pause", show=True),
        Binding("r", "resume_agent", "Resume", show=True),
        Binding("k", "kill_agent", "Kill", show=True),
        Binding("j", "move_down", "Down", show=False),
        Binding("k", "move_up", "Up", show=False),
        Binding("enter", "select", "Select", show=False),
        Binding("l", "view_logs", "Logs", show=True),
        Binding("d", "view_diff", "Diff", show=True),
        Binding("c", "commit", "Commit", show=False),
        Binding("escape", "cancel", "Cancel", show=False),
    ]

    TITLE = "Agent Orchestrator Dashboard"

    # Reactive properties
    selected_agent: reactive[Optional[str]] = reactive(None)
    refresh_interval: reactive[float] = reactive(1.0)

    def __init__(
        self,
        data_provider: Optional[Any] = None,
        refresh_interval: float = 1.0,
    ):
        """
        Initialize the dashboard.

        Args:
            data_provider: Optional data provider for agent/task info
            refresh_interval: Seconds between status refreshes
        """
        super().__init__()
        self._data_provider = data_provider
        self.refresh_interval = refresh_interval
        self._refresh_timer: Optional[Timer] = None

    def compose(self) -> ComposeResult:
        """Compose the dashboard layout."""
        yield Header()

        with Container(id="main-container"):
            with Vertical(id="left-panel"):
                yield AgentStatusPanel(id="agents-panel")
                yield TaskQueuePanel(id="task-queue-panel")

            with Vertical(id="right-panel"):
                yield ActiveTaskPanel(id="active-task-panel")
                yield RichLog(id="log-panel", highlight=True, markup=True)

        yield CostSummaryBar(id="cost-bar")
        yield Footer()

    def on_mount(self) -> None:
        """Start background refresh on mount."""
        self._refresh_timer = self.set_interval(
            self.refresh_interval,
            self._refresh_status,
        )
        logger.info("Dashboard mounted, starting refresh timer")

    async def _refresh_status(self) -> None:
        """Refresh all status displays."""
        try:
            # Get data from provider or use mock data
            if self._data_provider:
                agents = await self._data_provider.get_agents()
                tasks = await self._data_provider.get_tasks()
                active = await self._data_provider.get_active_task()
                costs = await self._data_provider.get_costs()
            else:
                agents = self._get_mock_agents()
                tasks = self._get_mock_tasks()
                active = self._get_mock_active_task()
                costs = self._get_mock_costs()

            # Update widgets
            agents_panel = self.query_one("#agents-panel", AgentStatusPanel)
            agents_panel.update_agents(agents)

            task_panel = self.query_one("#task-queue-panel", TaskQueuePanel)
            task_panel.update_tasks(tasks)

            active_panel = self.query_one("#active-task-panel", ActiveTaskPanel)
            active_panel.update_task(active)

            cost_bar = self.query_one("#cost-bar", CostSummaryBar)
            cost_bar.update_costs(costs)

        except Exception as e:
            logger.error(f"Error refreshing status: {e}")
            self._log_message(f"[red]Error refreshing: {e}[/red]")

    def _log_message(self, message: str) -> None:
        """Log a message to the log panel."""
        log_panel = self.query_one("#log-panel", RichLog)
        timestamp = datetime.now().strftime("%H:%M:%S")
        log_panel.write(f"[dim]{timestamp}[/dim] {message}")

    # Mock data methods for standalone testing
    def _get_mock_agents(self) -> list[dict]:
        """Get mock agent data."""
        return [
            {
                "agent_id": "claude-code",
                "status": "running",
                "health": "healthy",
                "usage_percent": 45,
                "requests_used": 20,
                "requests_limit": 45,
            },
            {
                "agent_id": "gemini-cli",
                "status": "idle",
                "health": "healthy",
                "usage_percent": 12,
                "requests_used": 120,
                "requests_limit": 1000,
            },
            {
                "agent_id": "codex-cli",
                "status": "running",
                "health": "degraded",
                "usage_percent": 78,
                "requests_used": 62,
                "requests_limit": 80,
            },
        ]

    def _get_mock_tasks(self) -> list[dict]:
        """Get mock task data."""
        return [
            {
                "task_id": "task-1",
                "description": "Implement user authentication",
                "agent_id": "claude-code",
                "status": "running",
                "wait_time": "-",
            },
            {
                "task_id": "task-2",
                "description": "Add API rate limiting",
                "agent_id": "claude-code",
                "status": "queued",
                "wait_time": "2m",
            },
            {
                "task_id": "task-3",
                "description": "Write unit tests",
                "agent_id": None,
                "status": "pending",
                "wait_time": "5m",
            },
        ]

    def _get_mock_active_task(self) -> Optional[dict]:
        """Get mock active task data."""
        return {
            "task_id": "task-1",
            "description": "Implement user authentication",
            "agent_id": "claude-code",
            "status": "running",
            "started_at": datetime.now().isoformat(),
            "duration_seconds": 204,
            "tokens_used": 12450,
            "tokens_limit": 50000,
            "output_lines": [
                "Creating auth middleware...",
                "Writing login endpoint...",
                "Adding password hashing...",
                "✓ 3 files modified",
            ],
        }

    def _get_mock_costs(self) -> dict:
        """Get mock cost data."""
        return {
            "today_usd": 12.45,
            "month_usd": 245.80,
            "tokens_today": 245000,
            "budget_percent": 65,
            "alerts": 2,
        }

    # Actions
    async def action_new_task(self) -> None:
        """Create a new task."""
        self._log_message("[green]Creating new task...[/green]")
        # TODO: Open task creation dialog

    async def action_pause_agent(self) -> None:
        """Pause selected agent."""
        if self.selected_agent:
            self._log_message(f"[yellow]Pausing {self.selected_agent}...[/yellow]")
            # TODO: Pause agent via orchestrator

    async def action_resume_agent(self) -> None:
        """Resume selected agent."""
        if self.selected_agent:
            self._log_message(f"[green]Resuming {self.selected_agent}...[/green]")
            # TODO: Resume agent via orchestrator

    async def action_kill_agent(self) -> None:
        """Kill selected agent."""
        if self.selected_agent:
            self._log_message(f"[red]Killing {self.selected_agent}...[/red]")
            # TODO: Kill agent via orchestrator

    async def action_view_logs(self) -> None:
        """View agent logs."""
        if self.selected_agent:
            self._log_message(f"[blue]Viewing logs for {self.selected_agent}...[/blue]")
            # TODO: Open log viewer

    async def action_view_diff(self) -> None:
        """View agent's file changes."""
        if self.selected_agent:
            self._log_message(f"[blue]Viewing diff for {self.selected_agent}...[/blue]")
            # TODO: Open diff viewer

    async def action_help(self) -> None:
        """Show help dialog."""
        self._log_message("[dim]Help: q=quit, n=new, p=pause, r=resume, k=kill, l=logs, d=diff[/dim]")

    async def action_move_down(self) -> None:
        """Move selection down."""
        agents_panel = self.query_one("#agents-panel", AgentStatusPanel)
        agents_panel.select_next()

    async def action_move_up(self) -> None:
        """Move selection up."""
        agents_panel = self.query_one("#agents-panel", AgentStatusPanel)
        agents_panel.select_previous()

    def watch_selected_agent(self, agent_id: Optional[str]) -> None:
        """React to agent selection changes."""
        if agent_id:
            self._log_message(f"Selected: {agent_id}")


class DashboardDataProvider:
    """
    Data provider interface for the dashboard.

    Implement this to connect the dashboard to your orchestrator.
    """

    async def get_agents(self) -> list[dict]:
        """Get list of agent statuses."""
        raise NotImplementedError

    async def get_tasks(self) -> list[dict]:
        """Get list of tasks."""
        raise NotImplementedError

    async def get_active_task(self) -> Optional[dict]:
        """Get currently active task details."""
        raise NotImplementedError

    async def get_costs(self) -> dict:
        """Get cost summary."""
        raise NotImplementedError


def run_dashboard(
    data_provider: Optional[DashboardDataProvider] = None,
    refresh_interval: float = 1.0,
) -> None:
    """
    Run the dashboard application.

    Args:
        data_provider: Optional data provider
        refresh_interval: Status refresh interval in seconds
    """
    app = OrchestratorDashboard(
        data_provider=data_provider,
        refresh_interval=refresh_interval,
    )
    app.run()
