import asyncio

from textual.app import App, ComposeResult
from textual.containers import VerticalScroll
from textual.widgets import Static, Input
from rich.text import Text

from hibiscus.constants import DEFAULT_TEXT, DIM_TEXT
from hibiscus.widgets import CounterWidget, colorize_sonnet_line
from hibiscus.experience import run_experience


class HibiscusApp(App):
    CSS = """
    Screen {
        background: #0a0a0f;
    }

    #scroll-container {
        scrollbar-size: 0 0;
    }

    .terminal-line {
        color: #c8c8d0;
        margin: 0;
        padding: 0 4;
    }

    .ascii-line {
        color: #89CFF0;
        margin: 0;
        padding: 0 4;
    }

    .counter-widget {
        text-align: center;
        text-style: bold;
        margin: 1 0;
        padding: 0 4;
        height: 3;
        content-align: center middle;
    }

    .valentine-line {
        margin: 0;
        padding: 0 4;
    }

    .sonnet-line {
        margin: 0;
        padding: 0 4;
    }

    #valentine-input {
        margin: 1 4 0 4;
        background: #0a0a0f;
        border: none;
        color: #e0e0e8;
        height: 3;
        display: none;
    }

    #valentine-input:focus {
        border: none;
    }
    """

    def __init__(self):
        super().__init__()
        self._input_future: asyncio.Future | None = None

    def compose(self) -> ComposeResult:
        with VerticalScroll(id="scroll-container"):
            pass
        yield Input(id="valentine-input", placeholder="type here...")

    def on_mount(self) -> None:
        self.run_worker(run_experience(self), exclusive=True)

    def _add_line(self, content, css_class: str = "terminal-line") -> Static:
        widget = Static(content, classes=css_class)
        scroll = self.query_one("#scroll-container", VerticalScroll)
        scroll.mount(widget)
        return widget

    def _mount_counter(self) -> CounterWidget:
        counter = CounterWidget(id="counter", classes="counter-widget")
        scroll = self.query_one("#scroll-container", VerticalScroll)
        scroll.mount(counter)
        return counter

    async def _scroll_down(self) -> None:
        scroll = self.query_one("#scroll-container", VerticalScroll)
        scroll.scroll_end(animate=True, duration=0.3)

    async def _type_text(self, text: str, color: str = DEFAULT_TEXT, speed: float = 0.035, css_class: str = "terminal-line", style: str = "") -> Static:
        rich_style = f"{style} {color}".strip() if style else color
        t = Text("", style=rich_style)
        widget = self._add_line(t, css_class)
        await self._scroll_down()

        for char in text:
            t.append(char, style=rich_style)
            widget.update(Text(t.plain, style=rich_style))
            await asyncio.sleep(speed)

        await self._scroll_down()
        return widget

    async def _type_slow(self, text: str, color: str = DEFAULT_TEXT, **kwargs) -> Static:
        return await self._type_text(text, color, speed=0.045, **kwargs)

    async def _type_fast(self, text: str, color: str = DEFAULT_TEXT, **kwargs) -> Static:
        return await self._type_text(text, color, speed=0.018, **kwargs)

    async def _add_blank(self) -> None:
        self._add_line(" ")
        await self._scroll_down()

    async def _pause(self, duration: float) -> None:
        dots_text = Text("...", style=DIM_TEXT)
        widget = self._add_line(dots_text)
        await asyncio.sleep(duration)
        widget.remove()

    async def _type_sonnet_line(self, text: str, line_idx: int) -> None:
        widget = self._add_line(Text(""), "sonnet-line")
        await self._scroll_down()

        for i in range(len(text)):
            partial = text[:i + 1]
            colored = colorize_sonnet_line(partial, line_idx)
            widget.update(colored)
            await asyncio.sleep(0.022)

        await self._scroll_down()

    async def _ask_input(self) -> str:
        inp = self.query_one("#valentine-input", Input)
        inp.styles.display = "block"
        inp.value = ""
        inp.focus()
        await self._scroll_down()

        self._input_future = asyncio.get_event_loop().create_future()
        result = await self._input_future
        self._input_future = None

        inp.styles.display = "none"
        inp.value = ""
        return result

    def on_input_submitted(self, event: Input.Submitted) -> None:
        if self._input_future and not self._input_future.done():
            self._input_future.set_result(event.value)


def main():
    app = HibiscusApp()
    app.run()


if __name__ == "__main__":
    main()
