//! Spectator mode types for match recording and playback.

use serde::{Deserialize, Serialize};

use crate::dto::{ActionInfo, GameEventDto, GameStateDto};
use crate::introspection::DecisionInsightsDto;

/// Configuration for starting a spectator match
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SpectatorConfig {
    /// Deck ID for player 1
    pub player1_deck_id: String,
    /// Bot type for player 1 (random, greedy, mcts, alphabeta)
    pub player1_bot_type: String,
    /// Deck ID for player 2
    pub player2_deck_id: String,
    /// Bot type for player 2 (random, greedy, mcts, alphabeta)
    pub player2_bot_type: String,
    /// Optional fixed seed for reproducibility
    pub seed: Option<u64>,
    /// Number of MCTS simulations per move (default: 100 for fast playback)
    /// Higher values = stronger play but slower computation
    #[serde(default = "default_mcts_simulations")]
    pub mcts_simulations: u32,
    /// Alpha-Beta search depth (default: 4 for fast playback)
    /// Higher values = stronger play but exponentially slower
    #[serde(default = "default_alphabeta_depth")]
    pub alphabeta_depth: u32,
}

fn default_mcts_simulations() -> u32 {
    100 // Fast default for debug builds
}

fn default_alphabeta_depth() -> u32 {
    4 // Fast default for debug builds
}

/// A single action in the spectator match with full context
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SpectatorAction {
    /// Turn number when this action occurred
    pub turn: u16,
    /// Which player took the action (1 or 2)
    pub player: u8,
    /// The action that was taken
    pub action: ActionInfo,
    /// Full game state after this action
    pub state_after: GameStateDto,
    /// Events triggered by this action (for animations)
    pub events: Vec<GameEventDto>,
    /// MCTS thinking data (if bot is MCTS) - legacy field
    pub thinking: Option<MctsThinkingDto>,
    /// AI decision insights with move scores and evaluation breakdown
    pub insights: Option<DecisionInsightsDto>,
    /// Time spent computing this move in milliseconds
    pub thinking_time_ms: u64,
}

/// MCTS thinking data for visualization
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MctsThinkingDto {
    /// Total MCTS simulations performed
    pub total_simulations: u32,
    /// Top candidate moves with statistics
    pub top_moves: Vec<MctsMoveDto>,
    /// Win rate of the selected move
    pub selected_win_rate: f32,
}

/// A candidate move considered by MCTS
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MctsMoveDto {
    /// The action being considered
    pub action: ActionInfo,
    /// Number of times this move was visited in the search tree
    pub visits: u32,
    /// Estimated win rate for this move (0.0 - 1.0)
    pub win_rate: f32,
}

/// Complete pre-computed spectator match
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SpectatorMatch {
    /// Unique match identifier
    pub id: String,
    /// Original configuration used to create this match
    pub config: SpectatorConfig,
    /// Game state before any actions (starting state)
    pub initial_state: GameStateDto,
    /// All actions in the match, in order
    pub actions: Vec<SpectatorAction>,
    /// Final result of the match
    pub result: SpectatorResult,
    /// Total number of turns in the match
    pub total_turns: u16,
    /// Display name for player 1's deck
    pub player1_deck_name: String,
    /// Display name for player 2's deck
    pub player2_deck_name: String,
    /// Display name for player 1's bot
    pub player1_bot_name: String,
    /// Display name for player 2's bot
    pub player2_bot_name: String,
    /// Evaluation history for timeline visualization
    pub eval_history: Vec<EvalPoint>,
    /// Key moments where evaluation swung significantly
    pub key_moments: Vec<KeyMoment>,
}

/// A point on the evaluation timeline
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EvalPoint {
    /// Action index (0-based)
    pub action_index: usize,
    /// Turn number
    pub turn: u16,
    /// Which player acted (1 or 2)
    pub player: u8,
    /// Evaluation score (positive = P1 advantage)
    pub eval_score: f32,
}

/// A key moment in the game (significant eval swing)
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct KeyMoment {
    /// Action index where this moment occurred
    pub action_index: usize,
    /// Turn number
    pub turn: u16,
    /// Which player acted
    pub player: u8,
    /// Description of the action
    pub action_description: String,
    /// Evaluation change (delta from previous)
    pub eval_delta: f32,
    /// New evaluation score after this action
    pub eval_after: f32,
    /// Type of moment
    pub moment_type: KeyMomentType,
}

/// Types of key moments
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum KeyMomentType {
    /// Large positive swing for P1
    P1Surge,
    /// Large positive swing for P2 (negative eval delta)
    P2Surge,
    /// Lead changed hands
    LeadChange,
    /// Game-deciding moment
    Decisive,
}

/// Result of a completed spectator match
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SpectatorResult {
    /// Winner (1 or 2), or None for draw
    pub winner: Option<u8>,
    /// Reason for game end (e.g., "LifeZero", "TurnLimit", "draw")
    pub reason: String,
    /// Player 1's final life total
    pub player1_final_life: i16,
    /// Player 2's final life total
    pub player2_final_life: i16,
}

/// Progress update during match computation (for future async support)
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[allow(dead_code)] // Reserved for future streaming progress updates
pub struct ComputeProgress {
    /// Current turn being computed
    pub current_turn: u16,
    /// Total actions computed so far
    pub actions_computed: usize,
    /// Whether computation is complete
    pub is_complete: bool,
    /// The completed match (only present when is_complete is true)
    pub match_data: Option<SpectatorMatch>,
}
