use async_trait::async_trait;
use serde_json::Value;
use crate::domain::{MarketUpdate, Fill, Order, Side};
use crate::indicators::IndicatorSet;
use std::collections::HashMap;

/// Context provided to strategies
pub struct StrategyContext {
    pub portfolio_value: f64,
    pub cash: f64,
    pub positions: HashMap<String, f64>,
    pub pending_orders: Vec<Order>,
    pub indicators: IndicatorSet,
}

/// Signal generated by a strategy
#[derive(Debug, Clone)]
pub struct Signal {
    pub symbol: String,
    pub action: SignalAction,
    pub quantity: Option<f64>,
    pub confidence: f64, // 0.0 to 1.0
    pub reason: String,
    pub metadata: Option<Value>,
}

#[derive(Debug, Clone)]
pub enum SignalAction {
    Buy,
    Sell,
    Close,
    Hold,
}

/// Core strategy trait with lifecycle methods
#[async_trait]
pub trait Strategy: Send + Sync {
    /// Called once when strategy is initialized
    async fn init(&mut self, context: &StrategyContext) -> Result<(), String>;
    
    /// Called when trading starts
    async fn on_start(&mut self) -> Result<(), String>;
    
    /// Called for each market data update
    async fn on_data(&mut self, data: &MarketUpdate, context: &StrategyContext) -> Vec<Signal>;
    
    /// Called when an order is filled
    async fn on_fill(&mut self, order_id: &str, fill: &Fill, context: &StrategyContext);
    
    /// Called periodically (e.g., every minute)
    async fn on_timer(&mut self, context: &StrategyContext) -> Vec<Signal> {
        Vec::new() // Default: no signals on timer
    }
    
    /// Called when trading stops
    async fn on_stop(&mut self) -> Result<(), String>;
    
    /// Get strategy name
    fn name(&self) -> &str;
    
    /// Get strategy parameters
    fn parameters(&self) -> Value;
    
    /// Update strategy parameters
    fn update_parameters(&mut self, params: Value) -> Result<(), String>;
}

/// Base implementation that strategies can extend
pub struct BaseStrategy {
    name: String,
    parameters: Value,
}

impl BaseStrategy {
    pub fn new(name: String, parameters: Value) -> Self {
        Self { name, parameters }
    }
}

#[async_trait]
impl Strategy for BaseStrategy {
    async fn init(&mut self, _context: &StrategyContext) -> Result<(), String> {
        Ok(())
    }
    
    async fn on_start(&mut self) -> Result<(), String> {
        Ok(())
    }
    
    async fn on_data(&mut self, _data: &MarketUpdate, _context: &StrategyContext) -> Vec<Signal> {
        Vec::new()
    }
    
    async fn on_fill(&mut self, _order_id: &str, _fill: &Fill, _context: &StrategyContext) {
        // Default: no action
    }
    
    async fn on_stop(&mut self) -> Result<(), String> {
        Ok(())
    }
    
    fn name(&self) -> &str {
        &self.name
    }
    
    fn parameters(&self) -> Value {
        self.parameters.clone()
    }
    
    fn update_parameters(&mut self, params: Value) -> Result<(), String> {
        self.parameters = params;
        Ok(())
    }
}