//! Event logging system.
//!
//! Captures all player actions as structured events that become
//! the foundation for narrative generation.

use bevy::prelude::*;
use std::collections::HashMap;

use crate::gameplay::narrative::CampaignHistory;

/// All possible game events that can occur in a campaign.
#[derive(Event, Debug, Clone)]
pub enum GameEvent {
    /// Player mined ore from an asteroid belt
    Mining(MiningEvent),
    /// Player bought or sold items at a station
    Trade(TradeEvent),
    /// Player engaged in combat
    Combat(CombatEvent),
    /// Player discovered a new system or POI
    Exploration(ExplorationEvent),
    /// Player docked at a station
    Docking(DockingEvent),
    /// Player accepted/abandoned/failed a mission
    Mission(MissionEvent),
    /// Custom event for extensible storytelling
    Custom(CustomEvent),
}

/// Event from mining activities.
#[derive(Debug, Clone)]
pub struct MiningEvent {
    pub timestamp: f64,
    pub location: String,
    pub ore_type: String,
    pub quantity: u32,
    pub duration_seconds: f32,
}

/// Event from trading activities.
#[derive(Debug, Clone)]
pub struct TradeEvent {
    pub timestamp: f64,
    pub station: String,
    pub faction: String,
    pub is_purchase: bool,
    pub item_name: String,
    pub quantity: u32,
    pub unit_price: f32,
    pub total_value: f32,
}

/// Event from combat activities.
#[derive(Debug, Clone)]
pub struct CombatEvent {
    pub timestamp: f64,
    pub location: String,
    pub opponent: String,
    pub opponent_faction: Option<String>,
    pub outcome: CombatOutcome,
    pub hull_remaining: f32,
    pub rewards_earned: Option<f32>,
}

/// Outcome of a combat engagement.
#[derive(Debug, Clone)]
pub enum CombatOutcome {
    Victory,
    Defeat,
    Retreat,
    Draw,
}

/// Event from exploration activities.
#[derive(Debug, Clone)]
pub struct ExplorationEvent {
    pub timestamp: f64,
    pub location: String,
    pub discovery_type: DiscoveryType,
    pub description: String,
}

/// Types of discoveries.
#[derive(Debug, Clone)]
pub enum DiscoveryType {
    NewSystem,
    NewStation,
    Anomaly,
    Derelict,
    ResourceDeposit,
}

/// Event from docking activities.
#[derive(Debug, Clone)]
pub struct DockingEvent {
    pub timestamp: f64,
    pub station: String,
    pub system: String,
    pub faction: String,
    pub visit_duration_seconds: f32,
}

/// Event from mission activities.
#[derive(Debug, Clone)]
pub struct MissionEvent {
    pub timestamp: f64,
    pub mission_id: String,
    pub mission_type: String,
    pub event_type: MissionEventType,
    pub outcome: Option<MissionOutcome>,
}

/// Type of mission event.
#[derive(Debug, Clone)]
pub enum MissionEventType {
    Accepted,
    Completed,
    Abandoned,
    Failed,
}

/// Outcome of a completed mission.
#[derive(Debug, Clone)]
pub enum MissionOutcome {
    Success,
    PartialSuccess,
    Failure,
}

/// Custom event for extensible storytelling.
#[derive(Debug, Clone)]
pub struct CustomEvent {
    pub timestamp: f64,
    pub event_type: String,
    pub title: String,
    pub description: String,
    pub metadata: HashMap<String, String>,
}

impl GameEvent {
    /// Get the timestamp of this event.
    pub fn timestamp(&self) -> f64 {
        match self {
            GameEvent::Mining(e) => e.timestamp,
            GameEvent::Trade(e) => e.timestamp,
            GameEvent::Combat(e) => e.timestamp,
            GameEvent::Exploration(e) => e.timestamp,
            GameEvent::Docking(e) => e.timestamp,
            GameEvent::Mission(e) => e.timestamp,
            GameEvent::Custom(e) => e.timestamp,
        }
    }

    /// Get a short title for this event.
    pub fn title(&self) -> String {
        match self {
            GameEvent::Mining(e) => format!("Mined {} {}", e.quantity, e.ore_type),
            GameEvent::Trade(e) => {
                if e.is_purchase {
                    format!("Purchased {} {}", e.quantity, e.item_name)
                } else {
                    format!("Sold {} {}", e.quantity, e.item_name)
                }
            }
            GameEvent::Combat(e) => match e.outcome {
                CombatOutcome::Victory => format!("Victory over {}", e.opponent),
                CombatOutcome::Defeat => format!("Defeated by {}", e.opponent),
                CombatOutcome::Retreat => format!("Retreated from {}", e.opponent),
                CombatOutcome::Draw => format!("Draw with {}", e.opponent),
            },
            GameEvent::Exploration(e) => match e.discovery_type {
                DiscoveryType::NewSystem => format!("Discovered system: {}", e.location),
                DiscoveryType::NewStation => format!("Discovered station: {}", e.location),
                DiscoveryType::Anomaly => format!("Found anomaly: {}", e.description),
                DiscoveryType::Derelict => format!("Found derelict: {}", e.description),
                DiscoveryType::ResourceDeposit => format!("Found resource: {}", e.description),
            },
            GameEvent::Docking(e) => format!("Docked at {}", e.station),
            GameEvent::Mission(e) => format!(
                "{:?} mission: {}",
                e.event_type, e.mission_id
            ),
            GameEvent::Custom(e) => e.title.clone(),
        }
    }

    /// Get the location where this event occurred.
    pub fn location(&self) -> String {
        match self {
            GameEvent::Mining(e) => e.location.clone(),
            GameEvent::Trade(e) => e.station.clone(),
            GameEvent::Combat(e) => e.location.clone(),
            GameEvent::Exploration(e) => e.location.clone(),
            GameEvent::Docking(e) => e.system.clone(),
            GameEvent::Mission(e) => "Unknown".to_string(),
            GameEvent::Custom(e) => e.metadata.get("location").cloned().unwrap_or_default(),
        }
    }
}

/// Log game events to campaign history.
///
/// This system listens for GameEvents and adds them to the CampaignHistory.
pub fn log_game_events(
    mut events: EventReader<GameEvent>,
    mut history: ResMut<CampaignHistory>,
) {
    for event in events.read() {
        bevy::log::debug!("Logging game event: {}", event.title());
        history.add_event(event.clone());
    }
}
