"""iEvo TUI — interactive terminal dashboard."""

from __future__ import annotations

from pathlib import Path

from textual.app import App, ComposeResult
from textual.binding import Binding
from textual.containers import VerticalScroll
from textual.reactive import reactive
from textual.widgets import (
    DataTable,
    Footer,
    Header,
    RichLog,
    Static,
    TabbedContent,
    TabPane,
    Tree,
)

from ievo.core.agent import AgentPackage
from ievo.core.config import AGENTS_DIR, find_project_root
from ievo.core.project import ProjectManifest

LOGO = r"""[green]
  ██╗ ███████╗██╗   ██╗ ██████╗
  ╚═╝ ██╔════╝██║   ██║██╔═══██╗
  ██╗ █████╗  ██║   ██║██║   ██║
  ██║ ██╔══╝  ╚██╗ ██╔╝██║   ██║
  ██║ ███████╗ ╚████╔╝ ╚██████╔╝
  ╚═╝ ╚══════╝  ╚═══╝   ╚═════╝[/green]"""


MODEL_COLORS = {
    "opus": "red",
    "sonnet": "magenta",
    "haiku": "cyan",
}


class IevoApp(App):
    """iEvo interactive dashboard."""

    TITLE = "iEvo"
    SUB_TITLE = "Self-evolving AI agent framework"

    CSS = """
    Screen {
        background: $surface;
    }

    #logo {
        height: auto;
        padding: 1 2;
        text-align: center;
    }

    #project-info {
        height: 3;
        padding: 0 2;
        color: $text-muted;
    }

    TabbedContent {
        height: 1fr;
    }

    #agents-table {
        height: 1fr;
    }

    #pipeline-view {
        padding: 1 2;
    }

    #evo-log {
        height: 1fr;
        padding: 0 1;
    }

    #project-tree {
        height: 1fr;
    }

    .section-title {
        padding: 0 1;
        color: $accent;
        text-style: bold;
    }

    #help-text {
        padding: 1 2;
        color: $text-muted;
    }

    #no-project {
        padding: 2 4;
        text-align: center;
    }
    """

    BINDINGS = [
        Binding("a", "tab('agents')", "Agents"),
        Binding("p", "tab('pipeline')", "Pipeline"),
        Binding("e", "tab('evolution')", "Evolution"),
        Binding("f", "tab('files')", "Files"),
        Binding("r", "refresh_data", "Refresh"),
        Binding("q", "quit", "Quit"),
    ]

    project_root: reactive[Path | None] = reactive(None)

    def on_mount(self) -> None:
        self.project_root = find_project_root()

    def compose(self) -> ComposeResult:
        yield Header()
        yield Static(LOGO, id="logo", markup=True)
        yield Static("", id="project-info")

        with TabbedContent(initial="agents"):
            with TabPane("Agents", id="agents"):
                yield DataTable(id="agents-table", zebra_stripes=True)

            with TabPane("Pipeline", id="pipeline"):
                yield VerticalScroll(
                    Static("", id="pipeline-view", markup=True),
                )

            with TabPane("Evolution", id="evolution"):
                yield RichLog(id="evo-log", highlight=True, markup=True)

            with TabPane("Files", id="files"):
                yield Tree("project", id="project-tree")

        yield Static("", id="help-text")
        yield Footer()

    def watch_project_root(self, root: Path | None) -> None:
        """Called when project_root changes."""
        info = self.query_one("#project-info", Static)
        if root is None:
            info.update("[dim]No project found. Run:[/dim] [bold]ievo init[/bold]")
            return

        manifest = ProjectManifest.load(root)
        info.update(
            f"[bold]{manifest.project}[/bold] [dim]v{manifest.version}[/dim]  [dim]{root}[/dim]"
        )
        self._load_agents(root, manifest)
        self._load_pipeline(manifest)
        self._load_evolution(root, manifest)
        self._load_file_tree(root)

    def _load_agents(self, root: Path, manifest: ProjectManifest) -> None:
        table = self.query_one("#agents-table", DataTable)
        table.clear(columns=True)
        table.add_columns("Agent", "Version", "Model", "EVO", "Description")

        for name, version in manifest.agents.items():
            agent_dir = root / AGENTS_DIR / name
            model = "sonnet"
            description = ""
            evo_count = 0

            try:
                pkg = AgentPackage.load(agent_dir)
                model = pkg.model.primary
                description = pkg.description
            except Exception:
                pass

            evo_log = agent_dir / "EVOLUTION_LOG.md"
            if evo_log.exists():
                evo_count = evo_log.read_text().count("\n## ")

            color = MODEL_COLORS.get(model, "white")
            table.add_row(
                name,
                version,
                f"[{color}]{model}[/{color}]",
                str(evo_count) if evo_count else "-",
                description,
            )

        if not manifest.agents:
            table.add_row("[dim]no agents[/dim]", "", "", "", "run: ievo add spec-writer")

    def _load_pipeline(self, manifest: ProjectManifest) -> None:
        view = self.query_one("#pipeline-view", Static)
        agents = list(manifest.agents.keys())

        if not agents:
            view.update("[dim]No agents installed.[/dim]")
            return

        pipeline = []
        pipeline.append(
            "[bold]SDD Pipeline[/bold]  "
            "[dim]— two human gates, everything between is automated[/dim]\n"
        )

        # Build pipeline diagram
        boxes = []
        for a in agents:
            color = "green" if a == "spec-writer" else "cyan" if a == "coder" else "magenta"
            boxes.append(
                f"[{color}]┌{'─' * (len(a) + 2)}┐[/{color}]\n"
                f"[{color}]│[/{color}] [bold]{a}[/bold] [{color}]│[/{color}]\n"
                f"[{color}]└{'─' * (len(a) + 2)}┘[/{color}]"
            )

        # Show as flow
        pipeline.append("  [bold green]YOU[/bold green]")
        pipeline.append("   [dim]│[/dim]")
        for i, box in enumerate(boxes):
            pipeline.append("   [dim]▼[/dim]")
            for line in box.split("\n"):
                pipeline.append(f"  {line}")
            if i < len(boxes) - 1:
                pipeline.append("   [dim]│[/dim]")
        pipeline.append("   [dim]▼[/dim]")
        pipeline.append("  [bold green]YOU[/bold green] [dim](review gate)[/dim]")

        view.update("\n".join(pipeline))

    def _load_evolution(self, root: Path, manifest: ProjectManifest) -> None:
        log_widget = self.query_one("#evo-log", RichLog)
        log_widget.clear()

        any_entries = False
        for name in manifest.agents:
            evo_log = root / AGENTS_DIR / name / "EVOLUTION_LOG.md"
            if evo_log.exists():
                content = evo_log.read_text().strip()
                if content and content != "# Evolution Log":
                    log_widget.write(f"[bold magenta]── {name} ──[/bold magenta]")
                    log_widget.write(content)
                    log_widget.write("")
                    any_entries = True

        if not any_entries:
            log_widget.write("[dim]No evolution entries yet.[/dim]")
            log_widget.write("[dim]Agents will learn from their mistakes over time.[/dim]")

    def _load_file_tree(self, root: Path) -> None:
        tree = self.query_one("#project-tree", Tree)
        tree.clear()
        tree.root.set_label(str(root.name))
        tree.root.expand()

        self._add_path_to_tree(tree.root, root, depth=0, max_depth=3)

    def _add_path_to_tree(self, node, path: Path, depth: int, max_depth: int) -> None:
        if depth >= max_depth:
            return

        try:
            entries = sorted(path.iterdir(), key=lambda p: (not p.is_dir(), p.name))
        except PermissionError:
            return

        for entry in entries:
            if entry.name.startswith("."):
                continue
            if entry.is_dir():
                branch = node.add(f"[bold]{entry.name}/[/bold]", expand=depth < 1)
                self._add_path_to_tree(branch, entry, depth + 1, max_depth)
            else:
                node.add_leaf(f"[dim]{entry.name}[/dim]")

    def action_tab(self, tab_id: str) -> None:
        self.query_one(TabbedContent).active = tab_id

    def action_refresh_data(self) -> None:
        self.project_root = find_project_root()


def run_tui() -> None:
    """Launch the iEvo TUI dashboard."""
    app = IevoApp()
    app.run()
