use debot_db::CandlePattern;
use rust_decimal::Decimal;

#[derive(Debug, Clone)]
pub struct Candle {
    pub open: Decimal,
    pub high: Decimal,
    pub low: Decimal,
    pub close: Decimal,
    pub timestamp: i64,
}

impl Candle {
    pub fn new(open: Decimal, high: Decimal, low: Decimal, close: Decimal, timestamp: i64) -> Self {
        Self {
            open,
            high,
            low,
            close,
            timestamp,
        }
    }

    pub fn update(&mut self, price: Decimal) {
        if price > self.high {
            self.high = price;
        }
        if price < self.low {
            self.low = price;
        }
        self.close = price;
    }

    pub fn detect_pattern(candles: &[Candle]) -> CandlePattern {
        if candles.len() < 3 {
            return CandlePattern::None;
        }

        let latest = &candles[candles.len() - 1];
        let prev = &candles[candles.len() - 2];
        let prev2 = &candles[candles.len() - 3];

        let body = (latest.close - latest.open).abs();
        let upper_shadow = latest.high - Decimal::max(latest.open, latest.close);
        let lower_shadow = Decimal::min(latest.open, latest.close) - latest.low;

        // Hammer or Inverted Hammer
        if lower_shadow > body * Decimal::from(2) && upper_shadow < body {
            return CandlePattern::Hammer;
        } else if upper_shadow > body * Decimal::from(2) && lower_shadow < body {
            return CandlePattern::InvertedHammer;
        }

        // Engulfing (Bullish or Bearish)
        if latest.close > latest.open && latest.close > prev.high && latest.open < prev.low {
            return CandlePattern::BullishEngulfing;
        } else if latest.open > latest.close && latest.open > prev.high && latest.close < prev.low {
            return CandlePattern::BearishEngulfing;
        }

        // Doji
        if body < Decimal::new(1, 1) * (latest.high - latest.low) {
            return CandlePattern::Doji;
        }

        // Marubozu
        if upper_shadow.is_zero() && lower_shadow.is_zero() {
            return CandlePattern::Marubozu;
        }

        // Spinning Top
        if upper_shadow > body && lower_shadow > body {
            return CandlePattern::SpinningTop;
        }

        // Harami (Bullish or Bearish)
        if (prev.open > prev.close
            && latest.open > latest.close
            && latest.open < prev.close
            && latest.close > prev.open)
            || (prev.open < prev.close
                && latest.open < latest.close
                && latest.open > prev.close
                && latest.close < prev.open)
        {
            return CandlePattern::Harami;
        }

        // Harami Cross
        if prev.close == prev.open && (prev.high - prev.low) > (prev.close - prev.open).abs() {
            if (latest.open > prev.close && latest.close < prev.open)
                || (latest.open < prev.close && latest.close > prev.open)
            {
                return CandlePattern::HaramiCross;
            }
        }

        // Morning Star
        if prev2.open > prev2.close
            && prev.open < prev.close
            && latest.open > latest.close
            && latest.close > (prev.open + prev.close) / Decimal::new(2, 0)
        {
            return CandlePattern::MorningStar;
        }

        // Evening Star
        if prev2.open < prev2.close
            && prev.open > prev.close
            && latest.open < latest.close
            && latest.close < (prev.open + prev.close) / Decimal::new(2, 0)
        {
            return CandlePattern::EveningStar;
        }

        // Three White Soldiers
        if prev2.close < prev2.open
            && prev.close > prev.open
            && latest.close > latest.open
            && prev2.close < prev.close
            && prev.close < latest.close
            && latest.open > prev.close
        {
            return CandlePattern::ThreeWhiteSoldiers;
        }

        // Three Black Crows
        if prev2.close > prev2.open
            && prev.close < prev.open
            && latest.close < latest.open
            && prev2.close > prev.close
            && prev.close > latest.close
            && latest.open < prev.close
        {
            return CandlePattern::ThreeBlackCrows;
        }

        // Piercing Pattern
        if prev.open > prev.close
            && latest.open < latest.close
            && latest.open < prev.close
            && latest.close > (prev.open + prev.close) / Decimal::new(2, 0)
        {
            return CandlePattern::PiercingPattern;
        }

        // Dark Cloud Cover
        if prev.open < prev.close
            && latest.open > latest.close
            && latest.open > prev.close
            && latest.close < (prev.open + prev.close) / Decimal::new(2, 0)
        {
            return CandlePattern::DarkCloudCover;
        }

        CandlePattern::None
    }
}
