//! Workflow risk validation types for the Foxhunt trading system
//!
//! These types define the structure for workflow-specific risk validation requests,
//! responses, and status information used throughout the risk management system.

use serde::{Deserialize, Serialize};

/// Workflow-specific risk validation request
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
/// WorkflowRiskRequest
/// 
/// Auto-generated documentation placeholder - enhance with specifics
pub struct WorkflowRiskRequest {
    /// Optional workflow identifier for tracking
    pub workflow_id: Option<String>,
    /// Account identifier for the risk request
    pub account_id: String,
    /// Symbol being traded
    pub symbol: Option<Symbol>,
    /// Order side (buy/sell)
    pub side: Side,
    /// Quantity to trade
    pub quantity: Option<Decimal>,
    /// Price for the order
    pub price: Option<Decimal>,
    /// Type of order
    pub order_type: OrderType,
    /// Optional strategy identifier
    pub strategy_id: Option<String>,
}

/// Workflow-specific risk validation response
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
/// WorkflowRiskResponse
/// 
/// Auto-generated documentation placeholder - enhance with specifics
pub struct WorkflowRiskResponse {
    /// Whether the risk validation approved the trade
    pub approved: bool,
    /// Optional rejection reason if not approved
    pub rejection_reason: Option<String>,
    /// Risk score for the proposed trade
    pub risk_score: f64,
    /// Available buying power for the account
    pub available_buying_power: Option<Decimal>,
    /// Position impact of the proposed trade
    pub position_impact: Option<Decimal>,
    /// Concentration risk as a percentage
    pub concentration_risk: Option<f64>,
    /// Validation latency in microseconds
    pub validation_latency_us: u64,
}

/// Workflow risk status for account monitoring
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
/// WorkflowRiskStatus
/// 
/// Auto-generated documentation placeholder - enhance with specifics
pub struct WorkflowRiskStatus {
    /// Account identifier
    pub account_id: String,
    /// Current portfolio value
    pub portfolio_value: Option<Decimal>,
    /// Available buying power
    pub available_buying_power: Option<Decimal>,
    /// Whether kill switch is active
    pub kill_switch_active: bool,
    /// Maximum single trade value allowed
    pub max_single_trade_value: Option<Decimal>,
}

impl WorkflowRiskRequest {
    /// Create a new workflow risk request
    #[must_use]
    pub const fn new(
        account_id: String,
        symbol: Symbol,
        side: Side,
        quantity: Decimal,
        price: Decimal,
        order_type: OrderType,
    ) -> Self {
        Self {
            workflow_id: None,
            account_id,
            symbol: Some(symbol),
            side,
            quantity: Some(quantity),
            price: Some(price),
            order_type,
            strategy_id: None,
        }
    }

    /// Set the workflow ID
    #[must_use]
    pub fn with_workflow_id(mut self, workflow_id: String) -> Self {
        self.workflow_id = Some(workflow_id);
        self
    }

    /// Set the strategy ID
    #[must_use]
    pub fn with_strategy_id(mut self, strategy_id: String) -> Self {
        self.strategy_id = Some(strategy_id);
        self
    }

    /// Get the trade value (quantity * price)
    #[must_use]
    pub fn trade_value(&self) -> Option<Decimal> {
        match (self.quantity, self.price) {
            (Some(qty), Some(price)) => Some(qty * price),
            _ => None,
        }
    }
}

impl WorkflowRiskResponse {
    /// Create a new approved response
    #[must_use]
    pub const fn approved(
        risk_score: f64,
        available_buying_power: Decimal,
        position_impact: Decimal,
        validation_latency_us: u64,
    ) -> Self {
        Self {
            approved: true,
            rejection_reason: None,
            risk_score,
            available_buying_power: Some(available_buying_power),
            position_impact: Some(position_impact),
            concentration_risk: None,
            validation_latency_us,
        }
    }

    /// Create a new rejected response
    #[must_use]
    pub const fn rejected(reason: String, validation_latency_us: u64) -> Self {
        Self {
            approved: false,
            rejection_reason: Some(reason),
            risk_score: 0.0,
            available_buying_power: None,
            position_impact: None,
            concentration_risk: None,
            validation_latency_us,
        }
    }

    /// Check if the response is approved
    #[must_use]
    pub const fn is_approved(&self) -> bool {
        self.approved
    }

    /// Get rejection reason if rejected
    #[must_use]
    pub fn rejection_reason(&self) -> Option<&str> {
        self.rejection_reason.as_deref()
    }
}

impl WorkflowRiskStatus {
    /// Create a new workflow risk status
    #[must_use]
    pub const fn new(account_id: String) -> Self {
        Self {
            account_id,
            portfolio_value: None,
            available_buying_power: None,
            kill_switch_active: false,
            max_single_trade_value: None,
        }
    }

    /// Set portfolio value
    #[must_use]
    pub const fn with_portfolio_value(mut self, value: Decimal) -> Self {
        self.portfolio_value = Some(value);
        self
    }

    /// Set available buying power
    #[must_use]
    pub const fn with_buying_power(mut self, power: Decimal) -> Self {
        self.available_buying_power = Some(power);
        self
    }

    /// Set kill switch status
    #[must_use]
    pub const fn with_kill_switch(mut self, active: bool) -> Self {
        self.kill_switch_active = active;
        self
    }

    /// Set maximum single trade value
    #[must_use]
    pub const fn with_max_trade_value(mut self, value: Decimal) -> Self {
        self.max_single_trade_value = Some(value);
        self
    }

    /// Check if trading is allowed
    #[must_use]
    pub const fn trading_allowed(&self) -> bool {
        !self.kill_switch_active
    }

    /// Check if a trade value is within limits
    #[must_use]
    pub fn trade_within_limits(&self, trade_value: Decimal) -> bool {
        match self.max_single_trade_value {
            Some(max_value) => trade_value <= max_value,
            None => true, // No limit set
        }
    }

    /// Check if sufficient buying power is available
    #[must_use]
    pub fn sufficient_buying_power(&self, required: Decimal) -> bool {
        match self.available_buying_power {
            Some(available) => available >= required,
            None => false, // Unknown buying power, assume insufficient
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::types::test_utils::test_symbols::*;
    // dec! macro now available via types::prelude::*

    #[test]
    fn test_workflow_risk_request_creation() {
        let symbol = test_symbol_1();
        let request = WorkflowRiskRequest::new(
            "ACC123".to_string(),
            symbol,
            Side::Buy,
            dec!(100),
            dec!(150.25),
            OrderType::Market,
        );

        assert_eq!(request.account_id, "ACC123");
        assert_eq!(request.side, Side::Buy);
        assert_eq!(request.quantity, Some(dec!(100)));
        assert_eq!(request.price, Some(dec!(150.25)));
        assert_eq!(request.order_type, OrderType::Market);
        assert!(request.workflow_id.is_none());
        assert!(request.strategy_id.is_none());
    }

    #[test]
    fn test_workflow_risk_request_with_ids() {
        let symbol = test_symbol_1();
        let request = WorkflowRiskRequest::new(
            "ACC123".to_string(),
            symbol,
            Side::Buy,
            dec!(100),
            dec!(150.25),
            OrderType::Market,
        )
        .with_workflow_id("WF001".to_string())
        .with_strategy_id("STRAT001".to_string());

        assert_eq!(request.workflow_id, Some("WF001".to_string()));
        assert_eq!(request.strategy_id, Some("STRAT001".to_string()));
    }

    #[test]
    fn test_workflow_risk_request_trade_value() {
        let symbol = test_symbol_1();
        let request = WorkflowRiskRequest::new(
            "ACC123".to_string(),
            symbol,
            Side::Buy,
            dec!(100),
            dec!(150.25),
            OrderType::Market,
        );

        assert_eq!(request.trade_value(), Some(dec!(15025.00)));
    }

    #[test]
    fn test_workflow_risk_request_trade_value_missing() {
        let mut request = WorkflowRiskRequest::new(
            "ACC123".to_string(),
            test_symbol_1(),
            Side::Buy,
            dec!(100),
            dec!(150.25),
            OrderType::Market,
        );
        request.quantity = None;

        assert_eq!(request.trade_value(), None);
    }

    #[test]
    fn test_workflow_risk_response_approved() {
        let response = WorkflowRiskResponse::approved(0.75, dec!(10000), dec!(5000), 150);

        assert!(response.is_approved());
        assert_eq!(response.risk_score, 0.75);
        assert_eq!(response.available_buying_power, Some(dec!(10000)));
        assert_eq!(response.position_impact, Some(dec!(5000)));
        assert_eq!(response.validation_latency_us, 150);
        assert!(response.rejection_reason().is_none());
    }

    #[test]
    fn test_workflow_risk_response_rejected() {
        let response = WorkflowRiskResponse::rejected("Insufficient buying power".to_string(), 125);

        assert!(!response.is_approved());
        assert_eq!(
            response.rejection_reason(),
    // Some variant
            Some("Insufficient buying power")
        );
        assert_eq!(response.validation_latency_us, 125);
        assert_eq!(response.risk_score, 0.0);
        assert!(response.available_buying_power.is_none());
    }

    #[test]
    fn test_workflow_risk_status_creation() {
        let status = WorkflowRiskStatus::new("ACC123".to_string());

        assert_eq!(status.account_id, "ACC123");
        assert!(status.portfolio_value.is_none());
        assert!(status.available_buying_power.is_none());
        assert!(!status.kill_switch_active);
        assert!(status.max_single_trade_value.is_none());
    }

    #[test]
    fn test_workflow_risk_status_builder() {
        let status = WorkflowRiskStatus::new("ACC123".to_string())
            .with_portfolio_value(dec!(100000))
            .with_buying_power(dec!(50000))
            .with_kill_switch(false)
            .with_max_trade_value(dec!(10000));

        assert_eq!(status.portfolio_value, Some(dec!(100000)));
        assert_eq!(status.available_buying_power, Some(dec!(50000)));
        assert!(!status.kill_switch_active);
        assert_eq!(status.max_single_trade_value, Some(dec!(10000)));
    }

    #[test]
    fn test_workflow_risk_status_trading_allowed() {
        let mut status = WorkflowRiskStatus::new("ACC123".to_string());
        assert!(status.trading_allowed());

        status = status.with_kill_switch(true);
        assert!(!status.trading_allowed());

        status = status.with_kill_switch(false);
        assert!(status.trading_allowed());
    }

    #[test]
    fn test_workflow_risk_status_trade_within_limits() {
        let status =
            WorkflowRiskStatus::new("ACC123".to_string()).with_max_trade_value(dec!(10000));

        assert!(status.trade_within_limits(dec!(5000)));
        assert!(status.trade_within_limits(dec!(10000)));
        assert!(!status.trade_within_limits(dec!(15000)));
    }

    #[test]
    fn test_workflow_risk_status_trade_within_limits_no_limit() {
        let status = WorkflowRiskStatus::new("ACC123".to_string());
        assert!(status.trade_within_limits(dec!(999999)));
    }

    #[test]
    fn test_workflow_risk_status_sufficient_buying_power() {
        let status = WorkflowRiskStatus::new("ACC123".to_string()).with_buying_power(dec!(10000));

        assert!(status.sufficient_buying_power(dec!(5000)));
        assert!(status.sufficient_buying_power(dec!(10000)));
        assert!(!status.sufficient_buying_power(dec!(15000)));
    }

    #[test]
    fn test_workflow_risk_status_sufficient_buying_power_unknown() {
        let status = WorkflowRiskStatus::new("ACC123".to_string());
        assert!(!status.sufficient_buying_power(dec!(1000)));
    }

    #[test]
    fn test_workflow_risk_types_serialization() {
        let symbol = test_symbol_1();
        let request = WorkflowRiskRequest::new(
            "ACC123".to_string(),
            symbol,
            Side::Buy,
            dec!(100),
            dec!(150.25),
            OrderType::Market,
        );

        let serialized = serde_json::to_string(&request).expect("Serialization failed");
        let deserialized: WorkflowRiskRequest =
            serde_json::from_str(&serialized).expect("Deserialization failed");

        assert_eq!(request, deserialized);
    }
}
