//! Diagnostic metrics for game state analysis.
//!
//! Provides structured metrics for evaluating board advantage, tempo,
//! resource efficiency, and combat effectiveness.

use super::collector::TurnSnapshot;

/// Board advantage metric.
///
/// Measures who's ahead at a given point in the game by combining
/// life differential, board attack differential, and board health differential.
#[derive(Clone, Debug, Default)]
pub struct BoardAdvantage {
    /// Life differential (P1 - P2).
    pub life_diff: i32,
    /// Board attack differential (P1 - P2).
    pub attack_diff: i32,
    /// Board health differential (P1 - P2).
    pub health_diff: i32,
    /// Creature count differential (P1 - P2).
    pub creature_diff: i32,
}

impl BoardAdvantage {
    /// Create a new board advantage metric from a snapshot.
    pub fn from_snapshot(snapshot: &TurnSnapshot) -> Self {
        Self {
            life_diff: snapshot.p1_life - snapshot.p2_life,
            attack_diff: snapshot.p1_total_attack - snapshot.p2_total_attack,
            health_diff: snapshot.p1_total_health - snapshot.p2_total_health,
            creature_diff: snapshot.p1_creatures as i32 - snapshot.p2_creatures as i32,
        }
    }

    /// Calculate the composite advantage score.
    ///
    /// Returns a normalized score where positive values favor P1 and
    /// negative values favor P2.
    pub fn score(&self) -> f64 {
        (self.life_diff as f64 + self.attack_diff as f64 + self.health_diff as f64) / 3.0
    }

    /// Determine which player is ahead.
    ///
    /// Returns Some(true) if P1 is ahead, Some(false) if P2 is ahead,
    /// or None if roughly equal (within threshold).
    pub fn leader(&self, threshold: f64) -> Option<bool> {
        let score = self.score();
        if score > threshold {
            Some(true) // P1 ahead
        } else if score < -threshold {
            Some(false) // P2 ahead
        } else {
            None // Even
        }
    }
}

/// Tempo metrics tracking initiative and early game events.
#[derive(Clone, Debug, Default)]
pub struct TempoMetrics {
    /// Turn when P1 played their first creature.
    pub p1_first_creature_turn: Option<u32>,
    /// Turn when P2 played their first creature.
    pub p2_first_creature_turn: Option<u32>,
}

impl TempoMetrics {
    /// Check who played a creature first.
    ///
    /// Returns Some(true) if P1 played first, Some(false) if P2,
    /// or None if data unavailable.
    pub fn first_creature_player(&self) -> Option<bool> {
        match (self.p1_first_creature_turn, self.p2_first_creature_turn) {
            (Some(t1), Some(t2)) => Some(t1 <= t2),
            (Some(_), None) => Some(true),
            (None, Some(_)) => Some(false),
            (None, None) => None,
        }
    }
}

/// Resource efficiency metrics.
///
/// Tracks how efficiently players convert essence into board presence.
#[derive(Clone, Debug, Default)]
pub struct ResourceEfficiency {
    /// Total essence spent by P1.
    pub p1_essence_spent: u32,
    /// Total essence spent by P2.
    pub p2_essence_spent: u32,
    /// Total board impact generated by P1 (attack + health of played creatures).
    pub p1_board_impact: i32,
    /// Total board impact generated by P2.
    pub p2_board_impact: i32,
}

impl ResourceEfficiency {
    /// Calculate P1's efficiency (board impact per essence spent).
    pub fn p1_efficiency(&self) -> f64 {
        if self.p1_essence_spent == 0 {
            0.0
        } else {
            self.p1_board_impact as f64 / self.p1_essence_spent as f64
        }
    }

    /// Calculate P2's efficiency (board impact per essence spent).
    pub fn p2_efficiency(&self) -> f64 {
        if self.p2_essence_spent == 0 {
            0.0
        } else {
            self.p2_board_impact as f64 / self.p2_essence_spent as f64
        }
    }

    /// Calculate efficiency differential (P1 - P2).
    pub fn efficiency_diff(&self) -> f64 {
        self.p1_efficiency() - self.p2_efficiency()
    }
}

/// Combat efficiency metrics.
///
/// Tracks damage dealt and taken by each player for trade analysis.
#[derive(Clone, Debug, Default)]
pub struct CombatEfficiency {
    /// Total damage dealt to enemy face by P1.
    pub p1_face_damage: u32,
    /// Total damage dealt to enemy face by P2.
    pub p2_face_damage: u32,
    /// Total damage dealt to enemy creatures by P1.
    pub p1_creature_damage: u32,
    /// Total damage dealt to enemy creatures by P2.
    pub p2_creature_damage: u32,
    /// Creatures killed by P1.
    pub p1_creatures_killed: u32,
    /// Creatures killed by P2.
    pub p2_creatures_killed: u32,
    /// Creatures lost by P1.
    pub p1_creatures_lost: u32,
    /// Creatures lost by P2.
    pub p2_creatures_lost: u32,
}

impl CombatEfficiency {
    /// Calculate P1's trade ratio (creatures killed / creatures lost).
    ///
    /// Returns:
    /// - `None` if no creatures were killed or lost (no trades)
    /// - `Some(f64::INFINITY)` if killed creatures but lost none (perfect)
    /// - `Some(ratio)` otherwise
    pub fn p1_trade_ratio(&self) -> Option<f64> {
        match (self.p1_creatures_killed, self.p1_creatures_lost) {
            (0, 0) => None,                    // No trades occurred
            (_, 0) => Some(f64::INFINITY), // Perfect: killed without losing
            (kills, losses) => Some(kills as f64 / losses as f64),
        }
    }

    /// Calculate P2's trade ratio (creatures killed / creatures lost).
    ///
    /// Returns:
    /// - `None` if no creatures were killed or lost (no trades)
    /// - `Some(f64::INFINITY)` if killed creatures but lost none (perfect)
    /// - `Some(ratio)` otherwise
    pub fn p2_trade_ratio(&self) -> Option<f64> {
        match (self.p2_creatures_killed, self.p2_creatures_lost) {
            (0, 0) => None,                    // No trades occurred
            (_, 0) => Some(f64::INFINITY), // Perfect: killed without losing
            (kills, losses) => Some(kills as f64 / losses as f64),
        }
    }

    /// Calculate P1's total damage output.
    pub fn p1_total_damage(&self) -> u32 {
        self.p1_face_damage + self.p1_creature_damage
    }

    /// Calculate P2's total damage output.
    pub fn p2_total_damage(&self) -> u32 {
        self.p2_face_damage + self.p2_creature_damage
    }

    /// Calculate damage efficiency (damage dealt vs received).
    pub fn p1_damage_efficiency(&self) -> f64 {
        let dealt = self.p1_total_damage() as f64;
        let received = self.p2_total_damage() as f64;
        if received == 0.0 {
            dealt
        } else {
            dealt / received
        }
    }
}

/// Aggregated metrics per turn for trend analysis.
#[derive(Clone, Debug, Default)]
pub struct TurnMetrics {
    /// Turn number.
    pub turn: u32,
    /// Board advantage at this turn.
    pub board_advantage: BoardAdvantage,
    /// Cumulative essence spent by P1 up to this turn.
    pub p1_cumulative_essence: u32,
    /// Cumulative essence spent by P2 up to this turn.
    pub p2_cumulative_essence: u32,
}

impl TurnMetrics {
    /// Create turn metrics from a snapshot.
    pub fn from_snapshot(snapshot: &TurnSnapshot, p1_spent: u32, p2_spent: u32) -> Self {
        Self {
            turn: snapshot.turn,
            board_advantage: BoardAdvantage::from_snapshot(snapshot),
            p1_cumulative_essence: p1_spent,
            p2_cumulative_essence: p2_spent,
        }
    }
}

/// Per-game metric summary.
#[derive(Clone, Debug, Default)]
pub struct GameMetrics {
    /// Per-turn metrics throughout the game.
    pub turn_metrics: Vec<TurnMetrics>,
    /// Tempo metrics for the game.
    pub tempo: TempoMetrics,
    /// Resource efficiency metrics.
    pub resource_efficiency: ResourceEfficiency,
    /// Combat efficiency metrics.
    pub combat_efficiency: CombatEfficiency,
    /// Average board advantage score (positive = P1 ahead).
    pub avg_board_advantage: f64,
    /// Number of turns P1 was ahead.
    pub turns_p1_ahead: u32,
    /// Number of turns P2 was ahead.
    pub turns_p2_ahead: u32,
    /// Number of turns roughly even.
    pub turns_even: u32,
    /// Winner of the game (None = draw).
    pub winner: Option<crate::types::PlayerId>,
    /// Who got first blood (first to deal damage to opponent).
    pub first_blood: Option<crate::types::PlayerId>,
}

impl GameMetrics {
    /// Calculate from turn metrics with a threshold for "even" determination.
    pub fn summarize(turn_metrics: &[TurnMetrics], threshold: f64) -> Self {
        let mut turns_p1_ahead = 0;
        let mut turns_p2_ahead = 0;
        let mut turns_even = 0;
        let mut total_advantage = 0.0;

        for tm in turn_metrics {
            let score = tm.board_advantage.score();
            total_advantage += score;

            match tm.board_advantage.leader(threshold) {
                Some(true) => turns_p1_ahead += 1,
                Some(false) => turns_p2_ahead += 1,
                None => turns_even += 1,
            }
        }

        let avg_board_advantage = if turn_metrics.is_empty() {
            0.0
        } else {
            total_advantage / turn_metrics.len() as f64
        };

        Self {
            turn_metrics: turn_metrics.to_vec(),
            avg_board_advantage,
            turns_p1_ahead,
            turns_p2_ahead,
            turns_even,
            ..Default::default()
        }
    }
}