"""Custom widgets for Fliiq TUI."""

import ast

from textual import events
from textual.app import ComposeResult
from textual.containers import ScrollableContainer
from textual.reactive import reactive
from textual.widgets import Collapsible, Input, OptionList, Static


def _format_tool_result(name: str, result: str) -> str:
    """Format a tool result into a human-readable one-liner."""
    # Try to parse as a Python dict/literal
    parsed = None
    try:
        parsed = ast.literal_eval(result)
    except (ValueError, SyntaxError):
        pass

    if isinstance(parsed, dict):
        # Shell-style results with stdout/stderr/exit_code
        if "exit_code" in parsed:
            code = parsed["exit_code"]
            stdout = str(parsed.get("stdout", "")).strip()
            stderr = str(parsed.get("stderr", "")).strip()
            if code != 0 and stderr:
                output = stderr[:150]
                return f"exit {code}: {output}"
            if stdout:
                return f"exit {code} | {stdout[:150]}"
            return f"exit {code}"
        # Error results
        if "error" in parsed:
            return f"error: {str(parsed['error'])[:150]}"
        # Generic dict — show keys
        keys = ", ".join(parsed.keys())
        return f"{{{keys}}}"

    # Plain string — truncate
    truncated = result[:200] if len(result) > 200 else result
    return truncated


class HeaderWidget(Static):
    """Header showing ant icon, version, and current working directory."""

    DEFAULT_CSS = """
    HeaderWidget {
        height: 3;
        background: $surface;
        border-bottom: solid $primary;
        padding: 0 1;
    }

    HeaderWidget .title {
        color: $text;
        text-style: bold;
    }

    HeaderWidget .cwd {
        color: $text-muted;
    }
    """

    def __init__(self, version: str, cwd: str) -> None:
        super().__init__()
        self.version = version
        self.cwd = cwd

    def compose(self) -> ComposeResult:
        yield Static(f"~(o.o)~  Fliiq v{self.version}", classes="title")
        yield Static(self.cwd, classes="cwd")


class Message(Static):
    """A single message in the conversation (user or assistant)."""

    DEFAULT_CSS = """
    Message {
        padding: 0 1;
        margin: 0 0 1 0;
        width: 100%;
    }

    Message.user {
        color: $primary;
    }

    Message.assistant {
        color: $text;
    }

    Message.thinking {
        color: $warning;
    }

    Message.tool {
        color: $text-muted;
    }
    """

    def __init__(self, content: str, role: str = "assistant") -> None:
        super().__init__(content)
        self.add_class(role)


class CompletionMessage(Static):
    """Styled completion message with green border — visually distinct 'done' state."""

    DEFAULT_CSS = """
    CompletionMessage {
        padding: 1 2;
        margin: 1 0;
        width: 100%;
        border: solid $success;
        color: $text;
    }
    """

    def __init__(self, content: str, iterations: str = "") -> None:
        header = f"[Completed — {iterations}]" if iterations else "[Completed]"
        super().__init__(f"{header}\n\n{content}")


class PlanApprovalMessage(Static):
    """Styled plan summary with yellow border — signals action required."""

    DEFAULT_CSS = """
    PlanApprovalMessage {
        padding: 1 2;
        margin: 1 0;
        width: 100%;
        border: solid $warning;
        color: $text;
    }
    """

    def __init__(self, summary: str) -> None:
        escaped = summary.replace("[", "\\[")
        super().__init__(f"Plan Summary:\n\n{escaped}")


class PlanApprovalSelector(OptionList):
    """Arrow-key option list for plan approval next steps."""

    DEFAULT_CSS = """
    PlanApprovalSelector {
        height: auto;
        max-height: 8;
        margin: 0 0 1 0;
        width: 100%;
        border: solid $warning;
    }
    """

    def __init__(self, options: list[dict], recommended: int = 1) -> None:
        self.option_data = options
        labels = []
        for i, opt in enumerate(options, 1):
            rec = " (recommended)" if i == recommended else ""
            labels.append(f"{opt['label']}{rec} — {opt['description']}")
        labels.append("Type your own response")
        super().__init__(*labels)
        if 1 <= recommended <= len(options):
            self.highlighted = recommended - 1


class ToolCallGroup(Collapsible):
    """Collapsible group of consecutive tool calls."""

    DEFAULT_CSS = """
    ToolCallGroup {
        padding: 0;
        margin: 0 0 1 0;
        width: 100%;
    }
    """

    def __init__(self) -> None:
        super().__init__(title="Tools (1)", collapsed=True)
        self._count = 0

    def add_tool_call(self, name: str, result_preview: str) -> None:
        formatted = _format_tool_result(name, result_preview)
        msg = Message(f"  [{name}] {formatted}", role="tool")
        self.mount(msg)
        self._count += 1
        self.title = f"Tools ({self._count})"


class MessageLog(ScrollableContainer):
    """Scrollable container for conversation messages."""

    DEFAULT_CSS = """
    MessageLog {
        height: 1fr;
        border-bottom: solid $primary;
        padding: 1;
    }
    """

    def add_message(self, content: str, role: str = "assistant") -> None:
        """Add a message to the log and scroll to bottom."""
        msg = Message(content, role)
        self.mount(msg)
        self.scroll_end(animate=False)

    def add_user_message(self, content: str) -> None:
        """Add a user message."""
        self.add_message(f"You: {content}", role="user")

    def add_assistant_message(self, content: str) -> None:
        """Add an assistant response."""
        self.add_message(f"Fliiq: {content}", role="assistant")

    def add_thinking(self, elapsed: str) -> Message:
        """Add thinking indicator, returns widget for updating."""
        msg = Message(f"~(o.o)~ Thinking... {elapsed}", role="thinking")
        self.mount(msg)
        self.scroll_end(animate=False)
        return msg

    def add_tool_call(self, name: str, result_preview: str) -> None:
        """Add tool call to a collapsible group. Creates new group if last child isn't one."""
        children = list(self.children)
        if children and isinstance(children[-1], ToolCallGroup):
            group = children[-1]
        else:
            group = ToolCallGroup()
            self.mount(group)
        group.add_tool_call(name, result_preview)
        self.scroll_end(animate=False)

    def add_completion_message(self, content: str, iterations: str = "") -> None:
        """Add a styled completion message."""
        widget = CompletionMessage(content, iterations)
        self.mount(widget)
        self.scroll_end(animate=False)

    def add_plan_approval(self, summary: str) -> None:
        """Add a yellow-bordered plan summary message."""
        widget = PlanApprovalMessage(summary)
        self.mount(widget)
        self.scroll_end(animate=False)

    def clear_messages(self) -> None:
        """Clear all messages and tool groups."""
        for child in list(self.children):
            child.remove()


class ModeInput(Static):
    """Input area with mode indicator."""

    DEFAULT_CSS = """
    ModeInput {
        height: 3;
        background: $surface;
        layout: horizontal;
        padding: 0 1;
    }

    ModeInput .mode-label {
        width: auto;
        padding-right: 1;
    }

    ModeInput .mode-autonomous {
        color: $success;
    }

    ModeInput .mode-supervised {
        color: $warning;
    }

    ModeInput .mode-plan {
        color: $error;
    }

    ModeInput Input {
        width: 1fr;
    }

    ModeInput .hint {
        width: auto;
        color: $text-muted;
        padding-left: 1;
    }
    """

    HINT_IDLE = "shift+tab: mode"
    HINT_RUNNING = "esc: cancel | shift+tab: mode"

    mode = reactive("autonomous")
    agent_running = reactive(False)

    def compose(self) -> ComposeResult:
        yield Static("autonomous", id="mode-label", classes="mode-label mode-autonomous")
        yield Input(placeholder="Type a message...", id="user-input")
        yield Static(self.HINT_IDLE, id="hint-label", classes="hint")

    def watch_agent_running(self, running: bool) -> None:
        """Update hint text based on agent running state."""
        hint = self.query_one("#hint-label", Static)
        hint.update(self.HINT_RUNNING if running else self.HINT_IDLE)

    def watch_mode(self, new_mode: str) -> None:
        """Update mode label when mode changes."""
        label = self.query_one("#mode-label", Static)
        label.update(new_mode)
        # Update classes
        label.remove_class("mode-autonomous", "mode-supervised", "mode-plan")
        label.add_class(f"mode-{new_mode}")

    def focus_input(self) -> None:
        """Focus the input field."""
        self.query_one("#user-input", Input).focus()

    @property
    def input_widget(self) -> Input:
        """Get the input widget."""
        return self.query_one("#user-input", Input)

    def on_key(self, event: events.Key) -> None:
        """Capture shift+tab before Input widget consumes it."""
        if event.key == "shift+tab":
            self.app.action_cycle_mode()
            event.stop()
