use serde::{Serialize, Deserialize};
use std::collections::VecDeque;

/// Common types and utilities for indicators

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PriceData {
    pub open: Vec<f64>,
    pub high: Vec<f64>,
    pub low: Vec<f64>,
    pub close: Vec<f64>,
    pub volume: Vec<f64>,
}

impl PriceData {
    pub fn new() -> Self {
        Self {
            open: Vec::new(),
            high: Vec::new(),
            low: Vec::new(),
            close: Vec::new(),
            volume: Vec::new(),
        }
    }
    
    pub fn len(&self) -> usize {
        self.close.len()
    }
    
    pub fn is_empty(&self) -> bool {
        self.close.is_empty()
    }
    
    /// Get typical price (high + low + close) / 3
    pub fn typical_prices(&self) -> Vec<f64> {
        self.high.iter()
            .zip(&self.low)
            .zip(&self.close)
            .map(|((h, l), c)| (h + l + c) / 3.0)
            .collect()
    }
    
    /// Get true range for ATR calculation
    pub fn true_ranges(&self) -> Vec<f64> {
        if self.len() < 2 {
            return vec![];
        }
        
        let mut ranges = Vec::with_capacity(self.len() - 1);
        for i in 1..self.len() {
            let high_low = self.high[i] - self.low[i];
            let high_close = (self.high[i] - self.close[i - 1]).abs();
            let low_close = (self.low[i] - self.close[i - 1]).abs();
            ranges.push(high_low.max(high_close).max(low_close));
        }
        ranges
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum IndicatorResult {
    Single(f64),
    Multiple(Vec<f64>),
    Series(Vec<f64>),
    MACD {
        macd: Vec<f64>,
        signal: Vec<f64>,
        histogram: Vec<f64>,
    },
    BollingerBands {
        middle: Vec<f64>,
        upper: Vec<f64>,
        lower: Vec<f64>,
    },
    Stochastic {
        k: Vec<f64>,
        d: Vec<f64>,
    },
}

#[derive(Debug, Clone)]
pub enum IndicatorError {
    InsufficientData { required: usize, actual: usize },
    InvalidParameter(String),
    CalculationError(String),
}

impl std::fmt::Display for IndicatorError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            IndicatorError::InsufficientData { required, actual } => {
                write!(f, "Insufficient data: required {}, got {}", required, actual)
            }
            IndicatorError::InvalidParameter(msg) => write!(f, "Invalid parameter: {}", msg),
            IndicatorError::CalculationError(msg) => write!(f, "Calculation error: {}", msg),
        }
    }
}

impl std::error::Error for IndicatorError {}

/// Rolling window for incremental calculations
pub struct RollingWindow<T> {
    window: VecDeque<T>,
    capacity: usize,
}

impl<T: Clone> RollingWindow<T> {
    pub fn new(capacity: usize) -> Self {
        Self {
            window: VecDeque::with_capacity(capacity),
            capacity,
        }
    }
    
    pub fn push(&mut self, value: T) {
        if self.window.len() >= self.capacity {
            self.window.pop_front();
        }
        self.window.push_back(value);
    }
    
    pub fn is_full(&self) -> bool {
        self.window.len() >= self.capacity
    }
    
    pub fn len(&self) -> usize {
        self.window.len()
    }
    
    pub fn iter(&self) -> impl Iterator<Item = &T> {
        self.window.iter()
    }
    
    pub fn as_slice(&self) -> Vec<T> {
        self.window.iter().cloned().collect()
    }
    
    pub fn clear(&mut self) {
        self.window.clear();
    }
}