from __future__ import annotations

from typing import TYPE_CHECKING

import chess
import chess.pgn
from textual.app import ComposeResult
from textual.screen import Screen
from textual.widgets import Static, Footer, Header, ProgressBar
from textual.containers import VerticalScroll
from textual import work
from rich.text import Text

from chess_cli.analysis import (
    MoveAnalysis,
    analyze_game,
    CLASSIFICATIONS,
    CLASSIFICATION_SYMBOLS,
)

if TYPE_CHECKING:
    from chess_cli.engine import EnginePlayer

CLASSIFICATION_RICH_COLORS = {
    "Best": "green",
    "Excellent": "green",
    "Good": "white",
    "Inaccuracy": "yellow",
    "Mistake": "#d78700",
    "Blunder": "red",
}


class AnalysisScreen(Screen):

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

#analysis-title {
    height: 1;
    margin: 2 2 0 2;
    text-style: bold;
}

#analysis-progress {
    margin: 1 3;
}

#results-scroll {
    height: 1fr;
    margin: 1 2;
}

#analysis-results {
    width: 100%;
    padding: 1 2;
}
"""

    BINDINGS = [
        ("q", "go_back", "Back"),
        ("escape", "go_back", "Back"),
    ]

    def __init__(
        self,
        pgn_game: chess.pgn.Game,
        engine: EnginePlayer,
        white_name: str | None = None,
        black_name: str | None = None,
    ) -> None:
        self.pgn_game = pgn_game
        self.engine = engine
        self.white_name = white_name or pgn_game.headers.get("White", "White")
        self.black_name = black_name or pgn_game.headers.get("Black", "Black")
        self.results: list[MoveAnalysis] = []
        super().__init__()

    def compose(self) -> ComposeResult:
        yield Header(show_clock=False)
        yield Static("  Analyzing game...", id="analysis-title")
        yield ProgressBar(id="analysis-progress", total=100, show_eta=True)
        yield VerticalScroll(
            Static("", id="analysis-results"),
            id="results-scroll",
        )
        yield Footer()

    def on_mount(self) -> None:
        self._run_analysis()

    def on_unmount(self) -> None:
        if self.engine:
            self.engine.quit()
            self.engine = None

    @work(thread=True)
    def _run_analysis(self) -> None:
        self.engine.set_full_strength()

        moves = list(self.pgn_game.mainline_moves())
        total = len(moves)

        def progress_callback(current: int, total: int) -> None:
            self.app.call_from_thread(self._update_progress, current, total)

        results = analyze_game(
            self.pgn_game,
            self.engine.engine,
            depth=18,
            progress_callback=progress_callback,
        )

        self.engine.restore_difficulty()
        self.app.call_from_thread(self._show_results, results)

    def _update_progress(self, current: int, total: int) -> None:
        bar = self.query_one("#analysis-progress", ProgressBar)
        bar.total = total
        bar.progress = current
        self.query_one("#analysis-title", Static).update(
            f"  Analyzing move {current}/{total}..."
        )

    def _show_results(self, results: list[MoveAnalysis]) -> None:
        self.results = results
        self.query_one("#analysis-title", Static).update("  Analysis Complete")
        self.query_one("#analysis-progress", ProgressBar).display = False

        text = self._format_results_rich(results)
        self.query_one("#analysis-results", Static).update(text)

    def _format_results_rich(self, results: list[MoveAnalysis]) -> Text:
        text = Text()

        white_name = self.white_name
        black_name = self.black_name

        # Move-by-move section
        text.append("\n")
        text.append("  Move-by-move:\n", style="bold")

        i = 0
        while i < len(results):
            entry = results[i]
            color = CLASSIFICATION_RICH_COLORS.get(entry.classification, "white")
            symbol = CLASSIFICATION_SYMBOLS.get(entry.classification, "")

            if entry.color == chess.WHITE:
                # White move
                loss_str = f"+{entry.cp_loss}cp" if entry.cp_loss > 0 else ""
                class_label = entry.classification
                if loss_str:
                    class_label += " " + loss_str

                text.append(f"    {entry.move_number}. {entry.san:<7} ")
                text.append(f"[{class_label}]", style=color)

                # Check for corresponding black move
                show_black_best = False
                black_entry = None
                if i + 1 < len(results) and results[i + 1].color == chess.BLACK:
                    black_entry = results[i + 1]
                    b_color = CLASSIFICATION_RICH_COLORS.get(
                        black_entry.classification, "white"
                    )
                    b_loss = (
                        f"+{black_entry.cp_loss}cp" if black_entry.cp_loss > 0 else ""
                    )
                    b_class_label = black_entry.classification
                    if b_loss:
                        b_class_label += " " + b_loss

                    text.append(f"  ...{black_entry.san:<7} ")
                    text.append(f"[{b_class_label}]", style=b_color)
                    i += 1
                    show_black_best = black_entry.classification not in (
                        "Best",
                        "Excellent",
                        "Good",
                    )

                text.append("\n")

                # Show best move hints for non-good moves
                if entry.classification not in ("Best", "Excellent", "Good"):
                    text.append(
                        f"      Best was: {entry.best_move_san}\n", style="dim"
                    )
                if show_black_best and black_entry is not None:
                    text.append(
                        f"      Best was: ...{black_entry.best_move_san}\n",
                        style="dim",
                    )
            else:
                # Black move without preceding white (unusual)
                b_color = CLASSIFICATION_RICH_COLORS.get(
                    entry.classification, "white"
                )
                b_loss = f"+{entry.cp_loss}cp" if entry.cp_loss > 0 else ""
                b_class_label = entry.classification
                if b_loss:
                    b_class_label += " " + b_loss

                text.append(f"    {entry.move_number}. ...{entry.san:<7} ")
                text.append(f"[{b_class_label}]", style=b_color)
                text.append("\n")

                if entry.classification not in ("Best", "Excellent", "Good"):
                    text.append(
                        f"      Best was: ...{entry.best_move_san}\n", style="dim"
                    )

            i += 1

        # Summary section
        text.append("\n")
        text.append("  Summary:\n", style="bold")

        white_moves = [m for m in results if m.color == chess.WHITE]
        black_moves = [m for m in results if m.color == chess.BLACK]

        text.append(f"    {'':15} {white_name:>8}  {black_name:>8}\n")
        for class_name, _ in CLASSIFICATIONS:
            w_count = sum(1 for m in white_moves if m.classification == class_name)
            b_count = sum(1 for m in black_moves if m.classification == class_name)
            row_color = CLASSIFICATION_RICH_COLORS.get(class_name, "white")
            label = class_name + ":"
            text.append(f"    {label:<15}", style=row_color)
            text.append(f" {w_count:>8}  {b_count:>8}\n")

        # Accuracy section
        w_acpl = sum(m.cp_loss for m in white_moves) / max(len(white_moves), 1)
        b_acpl = sum(m.cp_loss for m in black_moves) / max(len(black_moves), 1)
        w_accuracy = max(0.0, 100.0 - w_acpl / 3.0)
        b_accuracy = max(0.0, 100.0 - b_acpl / 3.0)

        text.append("\n")
        text.append(f"    {'Accuracy:':<15}", style="bold")
        text.append(f" {w_accuracy:>7.1f}%  {b_accuracy:>7.1f}%\n")
        text.append(f"    {'ACPL:':<15} {w_acpl:>7.0f}     {b_acpl:>7.0f}\n", style="dim")

        return text

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