"""Play screen — choose color/source and start a game or analyze PGN."""

from __future__ import annotations

import random
import shutil

import chess
from rich.text import Text
from textual.app import ComposeResult
from textual.screen import Screen
from textual.reactive import reactive
from textual.widgets import Static, Footer, Header, Button
from textual.containers import Vertical

from chess_cli.tui.screens.menu_widgets import MenuOption
from chess_cli.settings import load_settings

# ── Constants ────────────────────────────────────────────────────────

COLOR_OPTIONS = ["White", "Black", "Random"]
SOURCE_OPTIONS = ["Local (Stockfish)", "Lichess"]

_FOCUSABLE = ["opt-color", "opt-source", "btn-start", "btn-analyze", "btn-back"]


# ── PlayScreen ───────────────────────────────────────────────────────

class PlayScreen(Screen):

    DEFAULT_CSS = """
PlayScreen {
    align: center middle;
}

#play-container {
    width: 60;
    height: auto;
    max-height: 100%;
    border: heavy $primary;
    padding: 2 3;
    background: $surface;
    overflow-y: auto;
}

#play-title {
    text-align: center;
    width: 100%;
    margin-bottom: 2;
}

.section-header {
    width: 100%;
    height: 1;
    color: $text-muted;
    margin: 2 0 1 0;
    padding: 0 1;
}

#btn-start {
    width: 100%;
    margin-top: 1;
}

#btn-analyze {
    width: 100%;
    margin-top: 1;
}

#btn-back {
    width: 100%;
    margin-top: 1;
}

#status-bar {
    width: 100%;
    height: 1;
    margin-top: 2;
    color: $text-muted;
    padding: 0 1;
}
"""

    BINDINGS = [
        ("up", "focus_prev", "Up"),
        ("down", "focus_next", "Down"),
        ("left", "cycle_left", "\u25c0"),
        ("right", "cycle_right", "\u25b6"),
        ("enter", "select", "Select"),
        ("escape", "back", "Back"),
        ("q", "back", "Back"),
    ]

    color_index: reactive[int] = reactive(0)
    source_index: reactive[int] = reactive(0)
    focus_index: reactive[int] = reactive(0)

    def compose(self) -> ComposeResult:
        yield Header(show_clock=False)
        with Vertical(id="play-container"):
            yield Static("\u265a  Play", id="play-title")
            yield Static(
                "\u2500\u2500 Game Setup \u2500\u2500\u2500\u2500\u2500"
                "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
                "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
                "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
                classes="section-header",
            )
            yield MenuOption("Color", "opt-color")
            yield MenuOption("Source", "opt-source")
            yield Static(
                "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
                "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
                "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
                "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
                "\u2500\u2500\u2500\u2500",
                classes="section-header",
            )
            yield Button("\u265a Start Game", id="btn-start", variant="primary")
            yield Button("\u265b Analyze PGN", id="btn-analyze")
            yield Button("\u2190 Back", id="btn-back")
            yield Static("", id="status-bar")
        yield Footer()

    # ------------------------------------------------------------------
    # Lifecycle
    # ------------------------------------------------------------------

    def on_mount(self) -> None:
        self._render_color()
        self._render_source()
        self._render_status_bar()
        self._update_highlight()

    # ------------------------------------------------------------------
    # Rendering helpers
    # ------------------------------------------------------------------

    def _render_color(self) -> None:
        text = Text()
        for i, option in enumerate(COLOR_OPTIONS):
            if i > 0:
                text.append("   ")
            marker = "\u25c9" if i == self.color_index else "\u25cb"
            style = "bold" if i == self.color_index else "dim"
            text.append(f"{marker} {option}", style=style)
        try:
            self.query_one("#opt-color", MenuOption).set_value(text)
        except Exception:
            pass

    def _render_source(self) -> None:
        text = Text()
        for i, option in enumerate(SOURCE_OPTIONS):
            if i > 0:
                text.append("   ")
            marker = "\u25c9" if i == self.source_index else "\u25cb"
            style = "bold" if i == self.source_index else "dim"
            text.append(f"{marker} {option}", style=style)
        try:
            self.query_one("#opt-source", MenuOption).set_value(text)
        except Exception:
            pass

    def _render_status_bar(self) -> None:
        text = Text()
        if self.source_index == 1:  # Lichess
            settings = load_settings()
            has_token = bool(settings.lichess_api_token)
            text.append("Lichess: ", style="dim")
            text.append(
                "\u2713 ready" if has_token else "\u2717 no token",
                style="green" if has_token else "red",
            )
        else:
            sf_found = shutil.which("stockfish") is not None
            text.append("Stockfish: ", style="dim")
            text.append(
                "\u2713 detected" if sf_found else "\u2717 not found",
                style="green" if sf_found else "red",
            )
        try:
            self.query_one("#status-bar", Static).update(text)
        except Exception:
            pass

    # ------------------------------------------------------------------
    # Focus system
    # ------------------------------------------------------------------

    def _update_highlight(self) -> None:
        focusable = _FOCUSABLE
        for opt_id in ["opt-color", "opt-source"]:
            try:
                widget = self.query_one(f"#{opt_id}", MenuOption)
                widget.highlighted = focusable.index(opt_id) == self.focus_index
            except Exception:
                pass
        any_button_focused = False
        for btn_id in ["btn-start", "btn-analyze", "btn-back"]:
            try:
                btn = self.query_one(f"#{btn_id}", Button)
                idx = focusable.index(btn_id)
                if idx == self.focus_index:
                    btn.focus()
                    btn.add_class("highlighted")
                    any_button_focused = True
                else:
                    btn.remove_class("highlighted")
            except Exception:
                pass
        if not any_button_focused:
            self.set_focus(None)

    def watch_focus_index(self, value: int) -> None:
        self._update_highlight()

    def action_focus_prev(self) -> None:
        total = len(_FOCUSABLE)
        self.focus_index = (self.focus_index - 1) % total

    def action_focus_next(self) -> None:
        total = len(_FOCUSABLE)
        self.focus_index = (self.focus_index + 1) % total

    def action_cycle_left(self) -> None:
        self._cycle_focused(-1)

    def action_cycle_right(self) -> None:
        self._cycle_focused(1)

    def _cycle_focused(self, direction: int) -> None:
        if self.focus_index >= len(_FOCUSABLE):
            return
        current_id = _FOCUSABLE[self.focus_index]
        if current_id == "opt-color":
            self.color_index = (self.color_index + direction) % len(COLOR_OPTIONS)
        elif current_id == "opt-source":
            self.source_index = (self.source_index + direction) % len(SOURCE_OPTIONS)

    # ------------------------------------------------------------------
    # Watchers
    # ------------------------------------------------------------------

    def watch_color_index(self, value: int) -> None:
        self._render_color()

    def watch_source_index(self, value: int) -> None:
        self._render_source()
        self._render_status_bar()

    # ------------------------------------------------------------------
    # Actions
    # ------------------------------------------------------------------

    def action_select(self) -> None:
        if self.focus_index >= len(_FOCUSABLE):
            return
        current_id = _FOCUSABLE[self.focus_index]
        if current_id == "opt-color":
            self._cycle_focused(1)
        elif current_id == "opt-source":
            self._cycle_focused(1)
        elif current_id == "btn-start":
            self._start_game()
        elif current_id == "btn-analyze":
            self.action_analyze()
        elif current_id == "btn-back":
            self.app.pop_screen()

    def on_button_pressed(self, event: Button.Pressed) -> None:
        if event.button.id == "btn-start":
            self._start_game()
        elif event.button.id == "btn-analyze":
            self.action_analyze()
        elif event.button.id == "btn-back":
            self.app.pop_screen()

    def _start_game(self) -> None:
        # Resolve color
        if self.color_index == 0:
            color = chess.WHITE
        elif self.color_index == 1:
            color = chess.BLACK
        else:
            color = random.choice([chess.WHITE, chess.BLACK])

        settings = load_settings()

        if self.source_index == 1:  # Lichess
            if not settings.lichess_api_token:
                self.notify("Set your Lichess API token first.", severity="warning")
                return
            from chess_cli.lichess import LichessClient
            from chess_cli.tui.screens.bot_select import BotSelectScreen
            from chess_cli.tui.screens.engine_settings import ENGINE_PROFILES

            client = LichessClient(token=settings.lichess_api_token)

            # Get time control from saved lichess settings
            from chess_cli.tui.screens.lichess_settings import TIME_CONTROLS

            tc_idx = settings.lichess_time_control_index
            if tc_idx >= len(TIME_CONTROLS):
                tc_idx = 1
            limit, increment, _ = TIME_CONTROLS[tc_idx]

            def on_bot_selected(bot_info):
                if bot_info is None:
                    client.close()
                    return
                from chess_cli.tui.screens.game import GameScreen

                self.app.push_screen(GameScreen(
                    color=color,
                    lichess_client=client,
                    lichess_bot=bot_info,
                    clock_limit=limit,
                    clock_increment=increment,
                ))

            self.app.push_screen(BotSelectScreen(client), callback=on_bot_selected)
        else:  # Local Stockfish
            from chess_cli.tui.screens.game import GameScreen
            from chess_cli.tui.screens.engine_settings import (
                ENGINE_PROFILES,
                THREAD_OPTIONS,
                HASH_OPTIONS,
                MOVE_TIME_OPTIONS,
            )

            # Look up engine profile
            profile = None
            for p in ENGINE_PROFILES:
                if p.name == settings.engine_profile:
                    profile = p
                    break
            if profile is None:
                profile = ENGINE_PROFILES[0]

            if profile.name == "Custom":
                threads = settings.custom_threads
                hash_mb = settings.custom_hash_mb
                mt_idx = settings.custom_move_time_index
                move_time = (
                    MOVE_TIME_OPTIONS[mt_idx]
                    if mt_idx < len(MOVE_TIME_OPTIONS)
                    else None
                )
            else:
                threads = profile.threads
                hash_mb = profile.hash_mb
                move_time = profile.move_time

            self.app.push_screen(GameScreen(
                color=color,
                difficulty=settings.difficulty,
                threads=threads,
                hash_mb=hash_mb,
                move_time=move_time,
            ))

    def action_analyze(self) -> None:
        self.notify("Analysis from file not yet implemented")

    def action_back(self) -> None:
        self.app.pop_screen()
