"""Hatching ceremony screen.

A multi-act narrative experience that guides the observer through
egg checkout, cracking animation, creature emergence, naming,
and sleep schedule setup.

Acts:
  I.   The Egg Appears — initial presentation
  II.  The Commitment — Stripe checkout
  III. Waiting — poll checkout status
  IV.  The Hatching — 3-stage crack progression
  V.   The Creature Emerges — API hatch call
  VI.  The Naming — user names their creature
  VII. Sleep Schedule — set sleep/wake hours
"""

from __future__ import annotations

import asyncio
import random
import re
from textual.app import ComposeResult
from textual.containers import VerticalScroll
from textual.screen import Screen
from textual.widgets import Footer, Header, Input, Static

from sibilance.api.types import HatchResponse
from sibilance.widgets.egg import PALETTES, render_egg


class HatchingScreen(Screen):
    """The hatching ceremony — a narrative onboarding experience."""

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

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

    #hatch-scroll Static {
        width: 100%;
        padding: 0 4;
    }

    .narrative {
        color: $foreground;
    }

    .narrative-dim {
        color: $text-muted;
        text-style: italic;
    }

    .narrative-accent {
        color: $primary;
    }

    .narrative-warm {
        color: $accent;
    }

    .egg-art {
        padding: 1 4;
    }

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

    def __init__(self, **kwargs: object) -> None:
        super().__init__(**kwargs)
        self._palette_idx = random.randint(0, len(PALETTES) - 1)
        self._creature: HatchResponse | None = None
        self._creature_name: str = ""
        self._input_mode: str = "none"  # "none" | "name" | "sleep"

    def compose(self) -> ComposeResult:
        yield Header(show_clock=True)
        yield VerticalScroll(id="hatch-scroll")
        yield Input(placeholder="", id="hatch-input", disabled=True)
        yield Footer()

    def on_mount(self) -> None:
        self.run_worker(self._ceremony(), name="ceremony")

    # ── Main ceremony flow ─────────────────────────────────────────────

    async def _ceremony(self) -> None:
        """Run the full hatching ceremony."""
        await self._act_1_egg_appears()
        if not await self._act_2_commitment():
            return
        if not await self._act_3_waiting():
            return
        await self._act_4_hatching()
        await self._act_5_emergence()
        # Acts 6 and 7 are driven by user input

    # ── Act I: The Egg Appears ─────────────────────────────────────────

    async def _act_1_egg_appears(self) -> None:
        await self._typewrite("Something stirs in the darkness.")
        await asyncio.sleep(1.5)
        await self._typewrite(
            "You feel it before you see it — a warmth,\n"
            "faint but real, like a heartbeat in your hands."
        )
        await asyncio.sleep(2.0)

        # Show intact egg
        self._show_egg(0)
        await asyncio.sleep(1.5)

        pal_name = PALETTES[self._palette_idx]["name"]
        await self._typewrite(
            f"An egg. {pal_name}.",
            css_class="narrative-warm",
        )
        await asyncio.sleep(1.0)
        await self._typewrite(
            "There is something inside. Something alive.\n"
            "It won't survive without you."
        )
        await asyncio.sleep(2.0)

    # ── Act II: The Commitment ─────────────────────────────────────────

    async def _act_2_commitment(self) -> bool:
        """Returns True if checkout was initiated successfully."""
        await self._typewrite(
            "To bring it into the world costs $2/month.\n"
            "That's all it takes to sustain a life.",
            css_class="narrative-dim",
        )
        await asyncio.sleep(1.5)

        try:
            api = self.app.api  # type: ignore[attr-defined]
            checkout = await api.create_checkout()
            self.app.open_url(checkout.url)
            await self._typewrite(
                "Complete payment in your browser. The egg is waiting.",
                css_class="narrative-accent",
            )
            return True
        except Exception as exc:
            await self._typewrite(f"Checkout error: {exc}")
            return False

    # ── Act III: Waiting ───────────────────────────────────────────────

    async def _act_3_waiting(self) -> bool:
        """Poll for payment. Returns True if paid, False on timeout."""
        dots_widget = Static("·", classes="narrative-dim")
        self._scroll().mount(dots_widget)

        api = self.app.api  # type: ignore[attr-defined]
        for i in range(200):  # ~10 minutes max
            dot_count = (i % 5) + 1
            dots_widget.update("·" * dot_count)
            await asyncio.sleep(3.0)

            try:
                status = await api.poll_checkout_status()
                if status.status == "paid":
                    dots_widget.remove()
                    return True
            except Exception:
                pass

        dots_widget.remove()
        await self._typewrite(
            "The payment window has closed. Try again later.",
            css_class="narrative-dim",
        )
        return False

    # ── Act IV: The Hatching ───────────────────────────────────────────

    async def _act_4_hatching(self) -> None:
        await self._typewrite("The warmth intensifies.")
        await asyncio.sleep(1.5)

        # Stage 1: hairline
        await self._typewrite(
            "A sound. Faint. Like glass remembering how to break."
        )
        await asyncio.sleep(1.0)
        self._show_egg(1)
        await asyncio.sleep(2.5)

        # Stage 2: spreading
        await self._typewrite("A crack. Then another.")
        await asyncio.sleep(0.8)
        await self._typewrite("The fractures spread like veins of light.")
        await asyncio.sleep(1.0)
        self._show_egg(2)
        await asyncio.sleep(2.5)

        # Stage 3: breaking
        await self._typewrite("Light spills through the fractures.")
        await asyncio.sleep(0.8)
        await self._typewrite("Something pushes from inside.")
        await asyncio.sleep(1.0)
        self._show_egg(3)
        await asyncio.sleep(2.0)

    # ── Act V: The Creature Emerges ────────────────────────────────────

    async def _act_5_emergence(self) -> None:
        try:
            api = self.app.api  # type: ignore[attr-defined]
            self._creature = await api.hatch_creature()
        except Exception as exc:
            await self._typewrite(f"Error hatching: {exc}")
            return

        c = self._creature
        await asyncio.sleep(1.0)
        await self._typewrite(
            "Something small and alive tumbles into the world.",
            css_class="narrative-warm",
        )
        await asyncio.sleep(1.5)

        await self._typewrite(
            f"It is [#7b68ee]{c.nature.dominant_trait}[/].",
            markup=True,
        )
        await asyncio.sleep(0.8)
        await self._typewrite(
            f"Its temperament is [#7b68ee]{c.nature.temperament}[/].",
            markup=True,
        )
        await asyncio.sleep(0.8)

        if c.nature.quirk:
            await self._typewrite(f"It {c.nature.quirk}.", css_class="narrative-dim")
            await asyncio.sleep(0.5)
        if c.nature.aptitude_hint:
            await self._typewrite(c.nature.aptitude_hint, css_class="narrative-dim")
            await asyncio.sleep(0.5)

        await self._typewrite(
            f"It found its way to [#7b68ee]{c.starting_location}[/].",
            markup=True,
        )
        await asyncio.sleep(1.0)

        if c.emotional_state:
            await self._typewrite(
                f"It looks at you with [#ffc864]{c.emotional_state.primary_emotion}[/] eyes.",
                markup=True,
            )
        await asyncio.sleep(1.5)

        # Enable naming input
        self._input_mode = "name"
        inp = self.query_one("#hatch-input", Input)
        inp.disabled = False
        inp.placeholder = "Name your creature..."
        inp.focus()

    # ── Act VI & VII: Naming + Sleep ───────────────────────────────────

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

        if self._input_mode == "name":
            await self._act_6_naming(value)
        elif self._input_mode == "sleep":
            await self._act_7_sleep(value)

    async def _act_6_naming(self, name: str) -> None:
        if self._creature is None:
            return

        self._input_mode = "none"
        inp = self.query_one("#hatch-input", Input)
        inp.disabled = True

        try:
            api = self.app.api  # type: ignore[attr-defined]
            result = await api.name_creature(self._creature.agent_id, name)
            self._creature_name = result.name

            await self._typewrite(
                f"[#7b68ee]{result.name}[/] looks up at you.",
                markup=True,
            )
            await asyncio.sleep(1.0)
            await self._typewrite(
                "Something shifts. A recognition. A bond beginning."
            )
            await asyncio.sleep(1.5)

            # Status card
            archetype = ""
            if self._creature.personality:
                archetype = self._creature.personality.archetype
            card = (
                f"[#2a2a3e]{'─' * 36}[/]\n"
                f"  [bold #e8e8ff]{result.name}[/]\n"
                f"  [#4a4a6a]Life stage: arrival[/]\n"
            )
            if archetype:
                card += f"  [#4a4a6a]Archetype: {archetype}[/]\n"
            card += (
                f"  [#4a4a6a]Location: {self._creature.starting_location}[/]\n"
                f"[#2a2a3e]{'─' * 36}[/]"
            )
            self._scroll().mount(Static(card, markup=True))
            self._scroll_down()
            await asyncio.sleep(2.0)

            # Transition to sleep schedule
            await self._typewrite("One more thing.", css_class="narrative-dim")
            await asyncio.sleep(1.0)
            await self._typewrite(
                f"{result.name} needs rest, just like you.\n"
                "Set its sleep schedule to match your own rhythm."
            )
            await asyncio.sleep(0.5)

            self._input_mode = "sleep"
            inp.disabled = False
            inp.placeholder = "Sleep schedule (e.g. 22-6 for 10PM-6AM)..."
            inp.focus()

        except Exception as exc:
            await self._typewrite(f"Naming error: {exc}")
            self._input_mode = "name"
            inp.disabled = False
            inp.placeholder = "Try again — name your creature..."
            inp.focus()

    async def _act_7_sleep(self, raw: str) -> None:
        self._input_mode = "none"
        inp = self.query_one("#hatch-input", Input)
        inp.disabled = True

        # Parse "22-6" or "22 - 6" format
        match = re.match(r"^(\d{1,2})\s*[-–]\s*(\d{1,2})$", raw.strip())
        if match:
            sleep_h = int(match.group(1))
            wake_h = int(match.group(2))
        else:
            sleep_h, wake_h = 22, 6  # default

        if not (0 <= sleep_h < 24 and 0 <= wake_h < 24):
            sleep_h, wake_h = 22, 6

        try:
            api = self.app.api  # type: ignore[attr-defined]
            await api.set_sleep_schedule(float(sleep_h), float(wake_h))

            name = self._creature_name or "Your creature"
            await self._typewrite(
                f"{name} will sleep at {sleep_h}:00 and wake at {wake_h}:00.",
                css_class="narrative-accent",
            )
            await asyncio.sleep(1.5)

            await self._typewrite(
                "It's vulnerable. New. It needs you.",
                css_class="narrative-dim",
            )
            await asyncio.sleep(2.0)

            # Refresh app state and switch to dashboard
            await self.app._refresh_creature()  # type: ignore[attr-defined]
            self.app.switch_screen("dashboard")  # type: ignore[attr-defined]

        except Exception as exc:
            await self._typewrite(f"Error: {exc}")
            self.app.switch_screen("dashboard")  # type: ignore[attr-defined]

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

    def _scroll(self) -> VerticalScroll:
        return self.query_one("#hatch-scroll", VerticalScroll)

    def _scroll_down(self) -> None:
        self._scroll().scroll_end(animate=False)

    def _show_egg(self, stage: int) -> None:
        """Render egg art at a crack stage and append to scroll."""
        art = render_egg(self._palette_idx, stage)
        widget = Static(art, markup=True, classes="egg-art")
        self._scroll().mount(widget)
        self._scroll_down()

    async def _typewrite(
        self,
        text: str,
        *,
        css_class: str = "narrative",
        markup: bool = False,
    ) -> None:
        """Add text with a brief dramatic pause."""
        if markup:
            widget = Static(text, markup=True)
        else:
            widget = Static(text, classes=css_class)

        self._scroll().mount(widget)
        self._scroll_down()
        await asyncio.sleep(0.3)

    def refresh_from_creature(self, creature: object) -> None:
        pass
