use chrono::{DateTime, Utc};
use serde::{Serialize, Deserialize};
use crate::MarketData;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SignalType {
    Buy,
    Sell,
    Close,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Signal {
    pub symbol: String,
    pub signal_type: SignalType,
    pub strength: f64, // -1.0 to 1.0
    pub quantity: Option<f64>,
    pub reason: Option<String>,
    pub metadata: Option<serde_json::Value>,
}

// This trait will be implemented by Rust strategies
// TypeScript strategies will communicate through FFI
pub trait Strategy: Send + Sync {
    fn on_market_data(&mut self, data: &MarketData) -> Vec<Signal>;
    fn on_fill(&mut self, symbol: &str, quantity: f64, price: f64, side: &str);
    fn get_name(&self) -> &str;
    fn get_parameters(&self) -> serde_json::Value;
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StrategyCall {
    pub method: String,
    pub data: serde_json::Value,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StrategyResponse {
    pub signals: Vec<Signal>,
}

// Bridge for TypeScript strategies

// This will be used to wrap TypeScript strategies
pub struct TypeScriptStrategy {
    pub name: String,
    pub id: String,
    pub parameters: serde_json::Value,
    // Callback function will be injected from TypeScript
    pub callback: Option<Box<dyn Fn(StrategyCall) -> StrategyResponse + Send + Sync>>,
}

impl TypeScriptStrategy {
    pub fn new(name: String, id: String, parameters: serde_json::Value) -> Self {
        Self {
            name,
            id,
            parameters,
            callback: None,
        }
    }
}

impl Strategy for TypeScriptStrategy {
    fn on_market_data(&mut self, data: &MarketData) -> Vec<Signal> {
        if let Some(callback) = &self.callback {
            let call = StrategyCall {
                method: "on_market_data".to_string(),
                data: serde_json::to_value(data).unwrap_or_default(),
            };
            let response = callback(call);
            response.signals
        } else {
            Vec::new()
        }
    }
    
    fn on_fill(&mut self, symbol: &str, quantity: f64, price: f64, side: &str) {
        if let Some(callback) = &self.callback {
            let call = StrategyCall {
                method: "on_fill".to_string(),
                data: serde_json::json!({
                    "symbol": symbol,
                    "quantity": quantity,
                    "price": price,
                    "side": side
                }),
            };
            callback(call);
        }
    }
    
    fn get_name(&self) -> &str {
        &self.name
    }
    
    fn get_parameters(&self) -> serde_json::Value {
        self.parameters.clone()
    }
}