use napi_derive::napi;
use napi::{bindgen_prelude::*};
use crate::risk::{BetSizer, BetSizingParameters, MarketRegime, RiskModel};
use crate::orderbook::{OrderBookAnalytics, LiquidityProfile};
use crate::positions::Position;
use std::collections::HashMap;

#[napi]
pub struct RiskAnalyzer {
    risk_model: RiskModel,
    bet_sizer: BetSizer,
}

#[napi]
impl RiskAnalyzer {
    #[napi(constructor)]
    pub fn new(capital: f64, base_risk_per_trade: f64, lookback_period: u32) -> Self {
        Self {
            risk_model: RiskModel::new(lookback_period as usize),
            bet_sizer: BetSizer::new(capital, base_risk_per_trade),
        }
    }
    
    #[napi]
    pub fn update_returns(&mut self, symbol: String, returns: Vec<f64>) -> Result<()> {
        self.risk_model.update_returns(&symbol, returns);
        Ok(())
    }
    
    #[napi]
    pub fn calculate_portfolio_risk(&self, positions_json: String, prices_json: String) -> Result<String> {
        // Parse positions
        let positions_data: Vec<(String, f64, f64)> = serde_json::from_str(&positions_json)
            .map_err(|e| Error::from_reason(format!("Failed to parse positions: {}", e)))?;
        
        let mut positions = HashMap::new();
        for (symbol, quantity, avg_price) in positions_data {
            positions.insert(symbol.clone(), Position {
                symbol,
                quantity,
                average_price: avg_price,
                realized_pnl: 0.0,
                unrealized_pnl: 0.0,
                total_cost: quantity * avg_price,
                last_update: chrono::Utc::now(),
            });
        }
        
        // Parse prices
        let prices: HashMap<String, f64> = serde_json::from_str(&prices_json)
            .map_err(|e| Error::from_reason(format!("Failed to parse prices: {}", e)))?;
        
        // Calculate risk
        match self.risk_model.calculate_portfolio_risk(&positions, &prices) {
            Ok(risk) => Ok(serde_json::to_string(&risk).unwrap()),
            Err(e) => Err(Error::from_reason(e)),
        }
    }
    
    #[napi]
    pub fn calculate_position_size(
        &self,
        signal_strength: f64,
        signal_confidence: f64,
        volatility: f64,
        liquidity_score: f64,
        current_drawdown: f64,
        price: f64,
        stop_loss: Option<f64>,
        market_regime: String,
    ) -> Result<String> {
        let regime = match market_regime.as_str() {
            "trending" => MarketRegime::Trending,
            "range_bound" => MarketRegime::RangeBound,
            "high_volatility" => MarketRegime::HighVolatility,
            "low_volatility" => MarketRegime::LowVolatility,
            _ => MarketRegime::Transitioning,
        };
        
        let params = BetSizingParameters {
            signal_strength,
            signal_confidence,
            market_regime: regime,
            volatility,
            liquidity_score,
            correlation_exposure: 0.0, // Would be calculated from portfolio
            current_drawdown,
        };
        
        let position_size = self.bet_sizer.calculate_position_size(
            &params,
            price,
            stop_loss,
            None, // Historical performance
            None, // Orderbook analytics
            None, // Liquidity profile
        );
        
        Ok(serde_json::to_string(&position_size).unwrap())
    }
    
    #[napi]
    pub fn calculate_optimal_stop_loss(
        &self,
        entry_price: f64,
        volatility: f64,
        support_levels: Vec<f64>,
        atr: Option<f64>,
        is_long: bool,
    ) -> f64 {
        self.bet_sizer.calculate_optimal_stop_loss(
            entry_price,
            volatility,
            &support_levels,
            atr,
            is_long,
        )
    }
}

#[napi]
pub struct OrderbookAnalyzer {}

#[napi]
impl OrderbookAnalyzer {
    #[napi(constructor)]
    pub fn new() -> Self {
        Self {}
    }
    
    #[napi]
    pub fn analyze_orderbook(&self, snapshot_json: String) -> Result<String> {
        let snapshot: crate::OrderBookSnapshot = serde_json::from_str(&snapshot_json)
            .map_err(|e| Error::from_reason(format!("Failed to parse snapshot: {}", e)))?;
        
        match OrderBookAnalytics::calculate(&snapshot) {
            Some(analytics) => Ok(serde_json::to_string(&analytics).unwrap()),
            None => Err(Error::from_reason("Failed to calculate analytics")),
        }
    }
    
    #[napi]
    pub fn calculate_liquidity_profile(&self, snapshot_json: String) -> Result<String> {
        let snapshot: crate::OrderBookSnapshot = serde_json::from_str(&snapshot_json)
            .map_err(|e| Error::from_reason(format!("Failed to parse snapshot: {}", e)))?;
        
        let profile = LiquidityProfile::from_snapshot(&snapshot);
        Ok(serde_json::to_string(&profile).unwrap())
    }
    
    #[napi]
    pub fn calculate_market_impact(
        &self,
        snapshot_json: String,
        order_size_usd: f64,
        is_buy: bool,
    ) -> Result<String> {
        let snapshot: crate::OrderBookSnapshot = serde_json::from_str(&snapshot_json)
            .map_err(|e| Error::from_reason(format!("Failed to parse snapshot: {}", e)))?;
        
        let profile = LiquidityProfile::from_snapshot(&snapshot);
        let impact = profile.calculate_market_impact(order_size_usd, is_buy);
        
        Ok(serde_json::to_string(&impact).unwrap())
    }
}