"""Conversation screen — chat-style interface with the creature.

Layout:
  ┌──────────────────────────────────────┐
  │  [scrollable message area]           │
  │                                      │
  │  You: hello there                    │
  │  Creature: *typewriter*              │
  │  (curious) ●●●                       │
  │  Bond: trust +1.2%                   │
  │                                      │
  ├──────────────────────────────────────┤
  │  /feed  /guide  /gift                │
  ├──────────────────────────────────────┤
  │  > Say something...                  │
  └──────────────────────────────────────┘
"""

from __future__ import annotations

import asyncio

from textual.app import ComposeResult
from textual.containers import Horizontal, VerticalScroll
from textual.screen import Screen
from textual.widgets import Button, Footer, Header, Input, Label

from sibilance.api.types import CreatureStatus
from sibilance.widgets.message import (
    BondImpactDisplay,
    CreatureMessage,
    EmotionShift,
    SystemMessage,
    UserMessage,
)


class ConversationScreen(Screen):
    """Chat interface for talking to the creature."""

    DEFAULT_CSS = """
    ConversationScreen {
        layout: vertical;
    }

    #chat-scroll {
        height: 1fr;
        background: $background;
        scrollbar-color: $secondary;
        scrollbar-color-hover: $text-muted;
        scrollbar-color-active: $primary;
    }

    #action-bar {
        dock: bottom;
        height: 3;
        padding: 0 1;
        background: $surface;
        border-top: solid $secondary;
    }

    #action-bar Button {
        margin: 0 1 0 0;
        min-width: 10;
        height: 1;
        background: $panel;
        color: $text-muted;
        border: none;
    }

    #action-bar Button:hover {
        background: $secondary;
        color: $foreground;
    }

    #action-bar Button:focus {
        background: $secondary;
        color: $primary;
    }

    #chat-input {
        dock: bottom;
        height: 3;
        margin: 0 1;
    }

    #chat-header {
        dock: top;
        height: 1;
        padding: 0 2;
        background: $surface;
        color: $text-muted;
        border-bottom: solid $secondary;
    }
    """

    def __init__(self, **kwargs: object) -> None:
        super().__init__(**kwargs)
        self._busy = False
        self._input_mode: str = "talk"  # "talk" | "guide" | "gift"

    def compose(self) -> ComposeResult:
        yield Header(show_clock=True)
        creature: CreatureStatus | None = self.app.creature  # type: ignore[attr-defined]
        name = creature.name if creature else "???"
        yield Label(
            f"Conversation with {name}",
            id="chat-header",
        )
        yield VerticalScroll(id="chat-scroll")
        with Horizontal(id="action-bar"):
            yield Button("Feed", id="btn-feed")
            yield Button("Guide", id="btn-guide")
            yield Button("Gift", id="btn-gift")
        yield Input(
            placeholder="Say something...",
            id="chat-input",
        )
        yield Footer()

    def on_mount(self) -> None:
        """Show a welcome system message."""
        creature: CreatureStatus | None = self.app.creature  # type: ignore[attr-defined]
        if creature:
            emotion = creature.emotion.primary if creature.emotion else "calm"
            self._append(
                SystemMessage(
                    f"{creature.name} is feeling {emotion}. "
                    f"Say something, or use the action buttons below."
                )
            )

    # ── Input handling ────────────────────────────────────────────────

    async def on_input_submitted(self, event: Input.Submitted) -> None:
        """Handle chat input."""
        message = event.value.strip()
        if not message or self._busy:
            return

        event.input.value = ""

        # Check for slash commands
        if message.startswith("/"):
            await self._handle_slash(message)
            return

        # Route based on input mode (set by guide/gift buttons)
        if self._input_mode == "guide":
            self._input_mode = "talk"
            self.query_one("#chat-input", Input).placeholder = "Say something..."
            await self._do_guide(message)
        elif self._input_mode == "gift":
            self._input_mode = "talk"
            self.query_one("#chat-input", Input).placeholder = "Say something..."
            await self._do_gift(message)
        else:
            await self._send_talk(message)

    async def on_button_pressed(self, event: Button.Pressed) -> None:
        """Handle action bar button presses."""
        if self._busy:
            return

        btn_id = event.button.id
        if btn_id == "btn-feed":
            await self._do_feed()
        elif btn_id == "btn-guide":
            self._input_mode = "guide"
            self._append(SystemMessage("Type your guidance and press Enter."))
            inp = self.query_one("#chat-input", Input)
            inp.placeholder = "Your guidance..."
            inp.focus()
        elif btn_id == "btn-gift":
            self._input_mode = "gift"
            self._append(SystemMessage("Describe your gift and press Enter."))
            inp = self.query_one("#chat-input", Input)
            inp.placeholder = "Describe your gift..."
            inp.focus()

    # ── Slash commands ────────────────────────────────────────────────

    async def _handle_slash(self, raw: str) -> None:
        """Parse and execute /command."""
        parts = raw.strip().split(maxsplit=1)
        cmd = parts[0].lower()
        arg = parts[1] if len(parts) > 1 else ""

        if cmd == "/feed":
            await self._do_feed()
        elif cmd == "/guide" and arg:
            await self._do_guide(arg)
        elif cmd == "/gift" and arg:
            await self._do_gift(arg)
        elif cmd == "/guide":
            self._append(SystemMessage("Usage: /guide <your suggestion>"))
        elif cmd == "/gift":
            self._append(SystemMessage("Usage: /gift <description of gift>"))
        else:
            self._append(SystemMessage(f"Unknown command: {cmd}"))

    # ── Actions ───────────────────────────────────────────────────────

    async def _send_talk(self, message: str) -> None:
        """Send a talk message and display the response."""
        self._append(UserMessage(message))
        self._busy = True
        self._append(SystemMessage("Thinking..."))

        try:
            api = self.app.api  # type: ignore[attr-defined]
            result = await api.talk_to_creature(message)

            # Remove "Thinking..." message
            self._remove_last_system()

            # Creature response with typewriter
            self._append(
                CreatureMessage(result.creature_name, result.response)
            )

            # Wait for typewriter to finish (approximate)
            await asyncio.sleep(len(result.response) * 0.025 + 0.5)

            # Emotion shift
            if result.emotion:
                self._append(EmotionShift(result.emotion))

            # Bond impact
            if result.bond_impact:
                self._append(BondImpactDisplay(result.bond_impact))

            # Refresh creature state
            self.app.run_worker(  # type: ignore[attr-defined]
                self.app._refresh_creature(),  # type: ignore[attr-defined]
                name="refresh",
                exclusive=True,
            )
        except Exception as exc:
            self._remove_last_system()
            self._append(SystemMessage(f"Error: {exc}"))
        finally:
            self._busy = False

    async def _do_feed(self) -> None:
        """Feed the creature."""
        self._busy = True
        self._append(SystemMessage("Feeding..."))

        try:
            api = self.app.api  # type: ignore[attr-defined]
            result = await api.feed_creature()

            self._remove_last_system()

            self._append(
                CreatureMessage(result.creature_name, result.reaction)
            )

            await asyncio.sleep(len(result.reaction) * 0.025 + 0.5)

            if result.emotion:
                self._append(EmotionShift(result.emotion))
            if result.bond_impact:
                self._append(BondImpactDisplay(result.bond_impact))

            self.app.run_worker(  # type: ignore[attr-defined]
                self.app._refresh_creature(),  # type: ignore[attr-defined]
                name="refresh",
                exclusive=True,
            )
        except Exception as exc:
            self._remove_last_system()
            self._append(SystemMessage(f"Error: {exc}"))
        finally:
            self._busy = False

    async def _do_guide(self, message: str) -> None:
        """Send guidance to the creature."""
        self._append(UserMessage(f"[guidance] {message}"))
        self._busy = True
        self._append(SystemMessage("Suggesting..."))

        try:
            api = self.app.api  # type: ignore[attr-defined]
            result = await api.guide_creature(message)

            self._remove_last_system()
            self._append(
                SystemMessage(f"Guidance type: {result.guidance_type}")
            )
            if result.response:
                self._append(
                    CreatureMessage(
                        self._creature_name(), result.response
                    )
                )

            self.app.run_worker(  # type: ignore[attr-defined]
                self.app._refresh_creature(),  # type: ignore[attr-defined]
                name="refresh",
                exclusive=True,
            )
        except Exception as exc:
            self._remove_last_system()
            self._append(SystemMessage(f"Error: {exc}"))
        finally:
            self._busy = False
            # Reset input placeholder
            self.query_one("#chat-input", Input).placeholder = "Say something..."

    async def _do_gift(self, description: str) -> None:
        """Give a gift to the creature."""
        self._append(UserMessage(f"[gift] {description}"))
        self._busy = True
        self._append(SystemMessage("Offering gift..."))

        try:
            api = self.app.api  # type: ignore[attr-defined]
            result = await api.gift_creature(description)

            self._remove_last_system()

            self._append(
                CreatureMessage(
                    self._creature_name(), result.response
                )
            )

            await asyncio.sleep(len(result.response) * 0.025 + 0.5)

            if result.bond_impact:
                self._append(BondImpactDisplay(result.bond_impact))

            self.app.run_worker(  # type: ignore[attr-defined]
                self.app._refresh_creature(),  # type: ignore[attr-defined]
                name="refresh",
                exclusive=True,
            )
        except Exception as exc:
            self._remove_last_system()
            self._append(SystemMessage(f"Error: {exc}"))
        finally:
            self._busy = False
            self.query_one("#chat-input", Input).placeholder = "Say something..."

    # ── Helpers ────────────────────────────────────────────────────────

    def _append(self, widget: SystemMessage | UserMessage | CreatureMessage | EmotionShift | BondImpactDisplay) -> None:
        """Add a widget to the chat scroll and auto-scroll to bottom."""
        scroll = self.query_one("#chat-scroll", VerticalScroll)
        scroll.mount(widget)
        scroll.scroll_end(animate=False)

    def _remove_last_system(self) -> None:
        """Remove the last SystemMessage (e.g. 'Thinking...')."""
        try:
            scroll = self.query_one("#chat-scroll", VerticalScroll)
            children = list(scroll.children)
            for child in reversed(children):
                if isinstance(child, SystemMessage):
                    child.remove()
                    break
        except Exception:
            pass

    def _creature_name(self) -> str:
        """Get the creature's name from app state."""
        creature: CreatureStatus | None = self.app.creature  # type: ignore[attr-defined]
        return creature.name if creature else "???"

    def refresh_from_creature(self, creature: CreatureStatus) -> None:
        """Called when creature state changes — update header."""
        try:
            header = self.query_one("#chat-header", Label)
            header.update(f"Conversation with {creature.name}")
        except Exception:
            pass
