//! Trade signal derived from ensemble predictions.

use crate::inference_adapter::EnsemblePrediction;

/// Trade action mapped from ensemble direction.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TradeAction {
    Buy,
    Sell,
    Hold,
}

/// Signal emitted by ML ensemble for trading.
#[derive(Debug, Clone)]
pub struct TradeSignal {
    pub action: TradeAction,
    pub symbol: String,
    pub confidence: f64,
    pub direction: f64,
    pub timestamp_us: i64,
}

impl TradeSignal {
    /// Convert an ensemble prediction to a trade signal.
    ///
    /// Direction > 0.1 -> Buy, < -0.1 -> Sell, else Hold.
    pub fn from_prediction(pred: &EnsemblePrediction, symbol: &str) -> Self {
        let action = if pred.direction > 0.1 {
            TradeAction::Buy
        } else if pred.direction < -0.1 {
            TradeAction::Sell
        } else {
            TradeAction::Hold
        };
        Self {
            action,
            symbol: symbol.to_string(),
            confidence: pred.confidence,
            direction: pred.direction,
            timestamp_us: std::time::SystemTime::now()
                .duration_since(std::time::UNIX_EPOCH)
                .map(|d| d.as_micros() as i64)
                .unwrap_or(0),
        }
    }
}

impl std::fmt::Display for TradeAction {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Buy => write!(f, "BUY"),
            Self::Sell => write!(f, "SELL"),
            Self::Hold => write!(f, "HOLD"),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::inference_adapter::PredictionMeta;

    fn make_pred(direction: f64, confidence: f64) -> EnsemblePrediction {
        EnsemblePrediction {
            model_name: "TEST".into(),
            direction,
            confidence,
            metadata: PredictionMeta {
                latency_us: 0,
                quantiles: None,
                attention_weights: None,
                q_values: None,
            },
        }
    }

    #[test]
    fn test_buy_signal() {
        let signal = TradeSignal::from_prediction(&make_pred(0.6, 0.85), "6E.FUT");
        assert_eq!(signal.action, TradeAction::Buy);
        assert_eq!(signal.symbol, "6E.FUT");
    }

    #[test]
    fn test_sell_signal() {
        let signal = TradeSignal::from_prediction(&make_pred(-0.5, 0.9), "6E.FUT");
        assert_eq!(signal.action, TradeAction::Sell);
    }

    #[test]
    fn test_hold_signal() {
        let signal = TradeSignal::from_prediction(&make_pred(0.05, 0.3), "6E.FUT");
        assert_eq!(signal.action, TradeAction::Hold);
    }
}
