//! Application state -- view-model structs consumed by every cockpit.
//!
//! These are intentionally decoupled from protobuf types so the TUI layer
//! has zero coupling to the gRPC schema.

use std::collections::VecDeque;
use std::time::Instant;

// ---------------------------------------------------------------------------
// Connection status
// ---------------------------------------------------------------------------

/// Connection state for the gRPC streaming layer.
#[derive(Debug, Clone)]
pub enum ConnectionStatus {
    Connecting,
    Connected,
    Reconnecting { attempt: u32 },
    Error(String),
}

impl Default for ConnectionStatus {
    fn default() -> Self {
        Self::Connecting
    }
}

// ---------------------------------------------------------------------------
// Training cockpit sub-tab
// ---------------------------------------------------------------------------

/// Sub-tab within the Training cockpit.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum TrainingTab {
    #[default]
    Live,
    History,
}

/// A completed/failed training run from the history (ListTrainingJobs RPC).
pub struct TrainingHistoryEntry {
    pub job_id: String,
    pub model: String,
    pub status: String,
    pub final_loss: f32,
    pub best_val: f32,
    pub created_at: i64,
    pub started_at: i64,
    pub completed_at: i64,
    pub description: String,
}

// ---------------------------------------------------------------------------
// Top-level state
// ---------------------------------------------------------------------------

/// Root state shared across all seven cockpit views.
pub struct AppState {
    /// Active cockpit index (0..=6).
    pub current_cockpit: usize,
    /// Whether the help overlay is visible.
    pub show_help: bool,
    /// ML training sessions.
    pub training_sessions: Vec<TrainingSessionData>,
    /// Active K8s training jobs.
    pub active_jobs: u32,
    /// GPU telemetry.
    pub gpu: GpuData,
    /// Service health statuses.
    pub services: Vec<ServiceData>,
    /// Open trading positions.
    pub positions: Vec<PositionData>,
    /// Recent trade executions (ring buffer).
    pub executions: VecDeque<ExecutionData>,
    /// Recent order events (ring buffer).
    pub orders: VecDeque<OrderEventData>,
    /// Account-level summary.
    pub account: AccountData,
    /// Aggregated risk metrics.
    pub risk: RiskData,
    /// Recent risk alerts (ring buffer).
    pub risk_alerts: VecDeque<RiskAlertData>,
    /// ML model statuses.
    pub model_statuses: Vec<ModelStatusData>,
    /// Host / cluster resource usage.
    pub system_resources: SystemResources,
    /// Live data-feed information.
    pub data_feeds: Vec<DataFeedData>,
    /// Data cache statistics.
    pub data_cache: DataCacheData,
    /// System alerts from monitoring (ring buffer).
    pub alerts: VecDeque<AlertData>,
    /// K8s pod groups (from SubscribeClusterPods).
    pub pods: Vec<PodGroupData>,
    /// Currently selected pod group index.
    pub selected_pod_group: Option<usize>,
    /// Whether the selected pod group is expanded.
    pub pod_group_expanded: bool,
    /// Scroll offset for the pod table (number of rows to skip).
    pub pod_scroll_offset: usize,
    /// Currently selected training session index.
    pub selected_training_session: Option<usize>,
    /// Whether the selected training session detail panel is shown.
    pub training_detail_expanded: bool,
    /// Active sub-tab in the Training cockpit (Live vs History).
    pub training_tab: TrainingTab,
    /// Completed/failed training runs from history.
    pub training_history: Vec<TrainingHistoryEntry>,
    /// Currently selected history entry index.
    pub selected_history_entry: Option<usize>,
    /// Scroll offset for the per-epoch history table in the detail panel.
    pub epoch_scroll_offset: usize,
    /// Timestamp of the last data refresh.
    pub last_update: Instant,
    /// gRPC connection status.
    pub connection_status: ConnectionStatus,
}

impl Default for AppState {
    fn default() -> Self {
        Self {
            current_cockpit: 0,
            show_help: false,
            training_sessions: Vec::new(),
            active_jobs: 0,
            gpu: GpuData::default(),
            services: Vec::new(),
            positions: Vec::new(),
            executions: VecDeque::new(),
            orders: VecDeque::new(),
            account: AccountData::default(),
            risk: RiskData::default(),
            risk_alerts: VecDeque::new(),
            model_statuses: Vec::new(),
            system_resources: SystemResources::default(),
            data_feeds: Vec::new(),
            data_cache: DataCacheData::default(),
            alerts: VecDeque::new(),
            pods: Vec::new(),
            selected_pod_group: None,
            pod_group_expanded: false,
            pod_scroll_offset: 0,
            selected_training_session: None,
            training_detail_expanded: false,
            training_tab: TrainingTab::default(),
            training_history: Vec::new(),
            selected_history_entry: None,
            epoch_scroll_offset: 0,
            last_update: Instant::now(),
            connection_status: ConnectionStatus::default(),
        }
    }
}

// ---------------------------------------------------------------------------
// Per-epoch snapshot (accumulated from streaming updates)
// ---------------------------------------------------------------------------

/// Snapshot of key metrics at a single epoch boundary.
pub struct EpochSnapshot {
    pub epoch: u32,
    pub loss: f64,
    pub val_loss: f64,
    pub sharpe: f64,
    pub sortino: f64,
    pub win_rate: f64,
    pub max_dd: f64,
    pub profit_factor: f64,
    pub total_return: f64,
    pub total_trades: u32,
    pub q_value_mean: f64,
    pub gradient_norm: f64,
    pub learning_rate: f64,
    pub policy_entropy: f64,
    pub action_buy_pct: f64,
    pub action_sell_pct: f64,
    pub action_hold_pct: f64,
}

// ---------------------------------------------------------------------------
// Data sub-structs
// ---------------------------------------------------------------------------

/// A single ML training session.
pub struct TrainingSessionData {
    pub model: String,
    pub fold: String,
    pub is_hyperopt: bool,
    pub epoch: u32,
    pub loss: f64,
    pub val_loss: f64,
    pub batches_per_sec: f64,
    pub iteration_secs: f64,
    pub epoch_duration_secs: f64,
    // Financial metrics
    pub sharpe: f64,
    pub sortino: f64,
    pub win_rate: f64,
    pub max_dd: f64,
    pub profit_factor: f64,
    pub total_return: f64,
    pub total_trades: u32,
    // Action distribution
    pub action_buy_pct: f64,
    pub action_sell_pct: f64,
    pub action_hold_pct: f64,
    // RL diagnostics
    pub q_value_mean: f64,
    pub q_value_max: f64,
    pub policy_entropy: f64,
    pub kl_divergence: f64,
    pub advantage_mean: f64,
    pub replay_buffer_size: u32,
    // Gradient & training health
    pub gradient_norm: f64,
    pub learning_rate: f64,
    // Health counters
    pub nan_detected: u32,
    pub gradient_explosions: u32,
    pub feature_errors: u32,
    // Checkpoint
    pub checkpoint_saves: u32,
    pub checkpoint_failures: u32,
    // Hyperopt
    pub hyperopt_trial_current: u32,
    pub hyperopt_trial_total: u32,
    pub hyperopt_best_objective: f64,
    pub hyperopt_trials_failed: u32,
    pub hyperopt_trial_epoch: u32,
    pub hyperopt_elapsed_secs: f64,
    // Per-epoch history (accumulated across stream updates)
    pub epoch_history: Vec<EpochSnapshot>,
}

/// GPU telemetry snapshot.
pub struct GpuData {
    pub name: String,
    pub utilization: f64,
    pub memory_used_gb: f64,
    pub memory_total_gb: f64,
    pub temperature_c: u32,
    pub power_watts: u32,
    pub power_limit_watts: u32,
}

impl Default for GpuData {
    fn default() -> Self {
        Self {
            name: "N/A".into(),
            utilization: 0.0,
            memory_used_gb: 0.0,
            memory_total_gb: 0.0,
            temperature_c: 0,
            power_watts: 0,
            power_limit_watts: 0,
        }
    }
}

/// A backend microservice.
pub struct ServiceData {
    pub name: String,
    pub healthy: bool,
    pub uptime: String,
    pub version: String,
    /// Health-check round-trip latency in milliseconds.
    pub latency_ms: f64,
    /// Error reason when service is unhealthy.
    pub error: Option<String>,
}

/// An open trading position.
pub struct PositionData {
    pub symbol: String,
    pub qty: i64,
    pub entry_price: f64,
    pub market_price: f64,
    pub unrealized_pnl: f64,
}

/// A recent trade execution.
pub struct ExecutionData {
    pub time: String,
    pub symbol: String,
    pub side: String,
    pub qty: i64,
    pub price: f64,
    pub status: String,
}

/// Account-level financials.
pub struct AccountData {
    pub equity: f64,
    pub cash: f64,
    pub margin_used: f64,
    pub daily_pnl: f64,
    pub total_pnl: f64,
}

impl Default for AccountData {
    fn default() -> Self {
        Self {
            equity: 0.0,
            cash: 0.0,
            margin_used: 0.0,
            daily_pnl: 0.0,
            total_pnl: 0.0,
        }
    }
}

/// Kill-switch, drawdown, circuit-breaker, and position-limit data.
pub struct RiskData {
    pub global_kill_switch: Option<bool>,
    pub portfolio_kill_switch: Option<bool>,
    pub strategy_kill_switch: Option<bool>,
    pub instrument_kill_switch: Option<bool>,
    pub current_drawdown_pct: f64,
    pub max_drawdown_pct: f64,
    pub high_water_mark: f64,
    pub circuit_breakers: Vec<CircuitBreakerData>,
    pub position_limits: Vec<PositionLimitData>,
}

impl Default for RiskData {
    fn default() -> Self {
        Self {
            global_kill_switch: None,
            portfolio_kill_switch: None,
            strategy_kill_switch: None,
            instrument_kill_switch: None,
            current_drawdown_pct: 0.0,
            max_drawdown_pct: 0.0,
            high_water_mark: 0.0,
            circuit_breakers: Vec::new(),
            position_limits: Vec::new(),
        }
    }
}

/// A single circuit breaker.
pub struct CircuitBreakerData {
    pub name: String,
    pub threshold: Option<f64>,
    pub current: Option<f64>,
    pub tripped: bool,
}

/// Position-limit on a single instrument.
pub struct PositionLimitData {
    pub symbol: String,
    pub max_qty: i64,
    pub current_qty: i64,
}

/// System resource metrics.
pub struct SystemResources {
    pub cpu_usage_pct: f64,
    pub ram_used_gb: f64,
    pub ram_total_gb: f64,
    pub gpu_cluster_utilization: f64,
}

impl Default for SystemResources {
    fn default() -> Self {
        Self {
            cpu_usage_pct: 0.0,
            ram_used_gb: 0.0,
            ram_total_gb: 0.0,
            gpu_cluster_utilization: 0.0,
        }
    }
}

/// A single live data feed.
pub struct DataFeedData {
    pub symbol: String,
    pub records_per_sec: u64,
    pub latency_us: u64,
    pub status: String,
}

/// Aggregate data cache statistics.
pub struct DataCacheData {
    pub total_records: u64,
    pub cache_hit_rate: f64,
    pub disk_usage_gb: f64,
    pub oldest_date: String,
    pub newest_date: String,
}

impl Default for DataCacheData {
    fn default() -> Self {
        Self {
            total_records: 0,
            cache_hit_rate: 0.0,
            disk_usage_gb: 0.0,
            oldest_date: String::new(),
            newest_date: String::new(),
        }
    }
}

/// An order lifecycle event.
pub struct OrderEventData {
    pub time: String,
    pub order_id: String,
    pub symbol: String,
    pub side: String,
    pub status: String,
    pub qty: f64,
    pub filled_qty: f64,
}

/// A risk alert from the risk service.
pub struct RiskAlertData {
    pub time: String,
    pub severity: String,
    pub alert_type: String,
    pub message: String,
}

/// ML model operational status.
pub struct ModelStatusData {
    pub model_name: String,
    pub state: String,
    pub health: String,
    pub last_prediction: String,
}

/// A system-level alert from monitoring.
pub struct AlertData {
    pub time: String,
    pub severity: String,
    pub service: String,
    pub title: String,
}

/// A single K8s pod.
pub struct PodData {
    pub name: String,
    pub service: String,
    pub status: String,
    pub restarts: i32,
    pub age: String,
    pub node: String,
    pub ready: bool,
    pub version: String,
}

/// Pods grouped by service.
pub struct PodGroupData {
    pub service: String,
    pub pods: Vec<PodData>,
    pub ready_count: usize,
    pub total_count: usize,
}
