Documentation
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum TrendType {
    Up,
    Down,
    Any,
}

#[derive(Clone, Copy, Debug, Eq, Hash, Serialize, Deserialize)]
pub enum TradingStrategy {
    MarketMake,
    Inago(TrendType),
    MeanReversion(TrendType),
    PidController(TrendType),
    RandomInago(TrendType),
    RandomMeanReversion(TrendType),
    RandomPidController(TrendType),
    Hybrid,
    Rebalance,
}

impl TradingStrategy {
    pub fn is_market_make(&self) -> bool {
        matches!(self, TradingStrategy::MarketMake)
    }

    pub fn trend_type(&self) -> &TrendType {
        match self {
            TradingStrategy::Inago(t)
            | TradingStrategy::MeanReversion(t)
            | TradingStrategy::PidController(t)
            | TradingStrategy::RandomInago(t)
            | TradingStrategy::RandomMeanReversion(t)
            | TradingStrategy::RandomPidController(t) => t,
            TradingStrategy::Hybrid | TradingStrategy::Rebalance | TradingStrategy::MarketMake => {
                &TrendType::Any
            }
        }
    }
}

impl PartialEq for TradingStrategy {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            // Hybrid matches specific trends of Inago, MeanReversion, and PidController
            (TradingStrategy::Hybrid, TradingStrategy::Inago(TrendType::Up))
            | (TradingStrategy::Hybrid, TradingStrategy::Inago(TrendType::Down))
            | (TradingStrategy::Hybrid, TradingStrategy::MeanReversion(TrendType::Up))
            | (TradingStrategy::Hybrid, TradingStrategy::MeanReversion(TrendType::Down))
            | (TradingStrategy::Hybrid, TradingStrategy::PidController(TrendType::Up))
            | (TradingStrategy::Hybrid, TradingStrategy::PidController(TrendType::Down))
            | (TradingStrategy::Inago(TrendType::Up), TradingStrategy::Hybrid)
            | (TradingStrategy::Inago(TrendType::Down), TradingStrategy::Hybrid)
            | (TradingStrategy::MeanReversion(TrendType::Up), TradingStrategy::Hybrid)
            | (TradingStrategy::MeanReversion(TrendType::Down), TradingStrategy::Hybrid)
            | (TradingStrategy::PidController(TrendType::Up), TradingStrategy::Hybrid)
            | (TradingStrategy::PidController(TrendType::Down), TradingStrategy::Hybrid)
            | (TradingStrategy::Hybrid, TradingStrategy::Hybrid) => true,

            // Rebalance equals itself only
            (TradingStrategy::Rebalance, TradingStrategy::Rebalance) => true,

            // MarketMake
            (TradingStrategy::MarketMake, TradingStrategy::MarketMake) => true,

            // Inago
            (TradingStrategy::Inago(TrendType::Any), TradingStrategy::Inago(_))
            | (TradingStrategy::Inago(_), TradingStrategy::Inago(TrendType::Any)) => true,
            (TradingStrategy::Inago(t1), TradingStrategy::Inago(t2)) if t1 == t2 => true,

            // MeanReversion
            (TradingStrategy::MeanReversion(TrendType::Any), TradingStrategy::MeanReversion(_))
            | (TradingStrategy::MeanReversion(_), TradingStrategy::MeanReversion(TrendType::Any)) => {
                true
            }
            (TradingStrategy::MeanReversion(t1), TradingStrategy::MeanReversion(t2))
                if t1 == t2 =>
            {
                true
            }

            // RandomInago
            (TradingStrategy::RandomInago(TrendType::Any), TradingStrategy::RandomInago(_))
            | (TradingStrategy::RandomInago(_), TradingStrategy::RandomInago(TrendType::Any)) => {
                true
            }
            (TradingStrategy::RandomInago(t1), TradingStrategy::RandomInago(t2)) if t1 == t2 => {
                true
            }

            // RandomMeanReversion
            (
                TradingStrategy::RandomMeanReversion(TrendType::Any),
                TradingStrategy::RandomMeanReversion(_),
            )
            | (
                TradingStrategy::RandomMeanReversion(_),
                TradingStrategy::RandomMeanReversion(TrendType::Any),
            ) => true,
            (
                TradingStrategy::RandomMeanReversion(t1),
                TradingStrategy::RandomMeanReversion(t2),
            ) if t1 == t2 => true,

            // PidController
            (TradingStrategy::PidController(TrendType::Any), TradingStrategy::PidController(_))
            | (TradingStrategy::PidController(_), TradingStrategy::PidController(TrendType::Any)) => {
                true
            }
            (TradingStrategy::PidController(t1), TradingStrategy::PidController(t2))
                if t1 == t2 =>
            {
                true
            }

            // RandomPidController
            (
                TradingStrategy::RandomPidController(TrendType::Any),
                TradingStrategy::RandomPidController(_),
            )
            | (
                TradingStrategy::RandomPidController(_),
                TradingStrategy::RandomPidController(TrendType::Any),
            ) => true,
            (
                TradingStrategy::RandomPidController(t1),
                TradingStrategy::RandomPidController(t2),
            ) if t1 == t2 => true,

            _ => false,
        }
    }
}