from __future__ import annotations

import time

from textual.app import ComposeResult
from textual.message import Message
from textual.reactive import reactive
from textual.widget import Widget
from textual.widgets import Static

from ..models import Workspace

STALE_SECONDS = 30.0


class CardHeader(Static):
    pass


class CardState(Static):
    pass


class CardInfo(Static):
    pass


class CardTerm(Static):
    pass


class CardFooter(Static):
    pass


class WorkspaceCard(Widget):
    """A single workspace panel showing state, details, and terminal preview."""

    workspace: reactive[Workspace | None] = reactive(None, always_update=True)
    terminal_text: reactive[str] = reactive("", always_update=True)
    focused_card: reactive[bool] = reactive(False)
    _prev_text: str = ""
    _last_text_change: float = 0.0
    is_stale: bool = False

    DEFAULT_CSS = """
    WorkspaceCard {
        height: 100%;
        overflow-y: auto;
    }
    CardHeader {
        height: 1;
        background: $boost;
        color: $text;
        text-style: bold;
        padding: 0 1;
    }
    CardState {
        height: 1;
    }
    CardInfo {
        height: auto;
        max-height: 3;
        color: $text-muted;
    }
    CardTerm {
        height: 1fr;
        min-height: 5;
        padding: 0 1;
        color: $text-muted;
        background: $surface;
    }
    CardFooter {
        dock: bottom;
        height: 1;
        background: $boost;
        color: $text-muted;
    }
    """

    class CardFocused(Message):
        def __init__(self, workspace: Workspace) -> None:
            super().__init__()
            self.workspace = workspace

    def __init__(self, workspace: Workspace, **kwargs) -> None:
        super().__init__(**kwargs)
        self._init_workspace = workspace

    def compose(self) -> ComposeResult:
        yield CardHeader("")
        yield CardState("")
        yield CardInfo("")
        yield CardTerm("", markup=False)
        yield CardFooter("")

    def on_mount(self) -> None:
        self.workspace = self._init_workspace

    def on_click(self) -> None:
        if self.workspace:
            self.post_message(self.CardFocused(self.workspace))

    def watch_focused_card(self, focused: bool) -> None:
        self.set_class(focused, "card-focused")

    def watch_workspace(self, ws: Workspace | None) -> None:
        if ws is None:
            return
        self._render_header(ws)
        self._render_footer(ws)
        self._render_state(ws)
        self._render_info(ws)

    @staticmethod
    def _truncate_rules(text: str) -> str:
        """Shorten long horizontal rule lines (──────...) to a fixed width."""
        out = []
        for line in text.splitlines():
            stripped = line.lstrip()
            if len(stripped) > 20 and all(c == "─" for c in stripped):
                indent = line[: len(line) - len(stripped)]
                out.append(indent + "─" * 20)
            else:
                out.append(line)
        return "\n".join(out)

    def watch_terminal_text(self, text: str) -> None:
        try:
            now = time.monotonic()
            if text != self._prev_text:
                self._prev_text = text
                self._last_text_change = now
                if self.is_stale:
                    self.is_stale = False
                    if self.workspace:
                        self._render_state(self.workspace)
            elif self._last_text_change and (now - self._last_text_change) >= STALE_SECONDS:
                # Only mark stale if the workspace claims to be "running"
                if not self.is_stale and self.workspace and self.workspace.agent_state == "running":
                    self.is_stale = True
                    self._render_state(self.workspace)
                    self.remove_class("state-running")

            term = self.query_one(CardTerm)
            lines = text.splitlines()[-15:] if text else []
            content = "\n".join(lines) if lines else ""
            term.update(self._truncate_rules(content))
        except Exception:
            pass

    def _render_header(self, ws: Workspace) -> None:
        try:
            header = self.query_one(CardHeader)
            state = ws.agent_state
            if state == "running":
                icon = "[bold green]●[/]"
            elif state == "input":
                icon = "[bold yellow]◐[/]"
            elif state == "idle":
                icon = "[dim]○[/]"
            else:
                icon = "[dim]•[/]"

            unread = sum(1 for n in ws.notifications if not n.is_read)
            badge = f" [bold red]({unread})[/]" if unread else ""

            agents = ws.agents
            agent_info = f" [magenta]{len(agents)}a[/]" if agents else ""

            header.update(f"{icon} [bold]{ws.title.upper()}[/]{agent_info}{badge}")
        except Exception:
            pass

    def _render_state(self, ws: Workspace) -> None:
        try:
            state_w = self.query_one(CardState)
            state = ws.agent_state
            # If output hasn't changed in 30s and state is "running", show idle
            if self.is_stale and state == "running":
                state = "idle"
            if state == "running":
                text = "[green bold]▶ Running[/]"
            elif state == "input":
                text = "[yellow bold]⏸ Waiting for input[/]"
            elif state == "idle":
                text = "[dim]■ Idle[/]"
            else:
                text = "[dim]  No agent[/]"
            state_w.update(f" {text}")
        except Exception:
            pass

    def _render_info(self, ws: Workspace) -> None:
        try:
            info = self.query_one(CardInfo)
            sb = ws.sidebar
            parts = []

            if sb.cwd and sb.cwd != "none":
                short = self._short_cwd(sb.cwd)
                parts.append(f" [dim]cwd:[/] {short}")
            if sb.pr and sb.pr != "none":
                # Extract URL and make it clickable
                pr_parts = sb.pr.split()
                url = next((p for p in pr_parts if p.startswith("http")), None)
                label = " ".join(p for p in pr_parts if not p.startswith("http"))
                if url:
                    parts.append(f" [dim]pr:[/]  [@click=app.open_link('{url}')][underline]{label}[/underline][/]")
                else:
                    parts.append(f" [dim]pr:[/]  {sb.pr}")
            if sb.progress and sb.progress != "none":
                parts.append(f" [dim]prog:[/] {sb.progress}")

            unread = [n for n in ws.notifications if not n.is_read]
            if unread:
                parts.append(f" [red]{unread[0].title}: {unread[0].body[:40]}[/]")

            info.update("\n".join(parts) if parts else "")
        except Exception:
            pass

    @staticmethod
    def _short_cwd(cwd: str) -> str:
        """Shorten path to ~/.../last_folder format."""
        from pathlib import Path
        home = str(Path.home())
        path = cwd.replace(home, "~")
        parts = path.split("/")
        if len(parts) > 3:
            return f"{parts[0]}/.../{parts[-1]}"
        return path

    def _render_footer(self, ws: Workspace) -> None:
        try:
            footer = self.query_one(CardFooter)
            sb = ws.sidebar
            branch = ""
            if sb.git_branch and sb.git_branch != "none":
                branch = f" {sb.git_branch}"
            footer.update(f"[dim]{branch}[/]")
        except Exception:
            pass
