use std::fs;

use termichart_core::{Candle, DataAdapter, Point, Result, TermichartError};

/// A [`DataAdapter`] that parses candle or point data from a JSON string.
pub struct JsonAdapter {
    data: String,
}

impl JsonAdapter {
    /// Creates a new `JsonAdapter` from a raw JSON string.
    pub fn from_str(s: &str) -> Self {
        Self {
            data: s.to_owned(),
        }
    }

    /// Creates a new `JsonAdapter` by reading the contents of a file.
    pub fn from_file(path: &str) -> Result<Self> {
        let data = fs::read_to_string(path)?;
        Ok(Self { data })
    }
}

impl DataAdapter for JsonAdapter {
    fn candles(&self) -> Result<Vec<Candle>> {
        serde_json::from_str(&self.data).map_err(|e| TermichartError::ParseError(e.to_string()))
    }

    fn points(&self) -> Result<Vec<Point>> {
        serde_json::from_str(&self.data).map_err(|e| TermichartError::ParseError(e.to_string()))
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parse_candles_from_json() {
        let json = r#"[
            {"time":1.0,"open":10.0,"high":15.0,"low":9.0,"close":14.0,"volume":100.0},
            {"time":2.0,"open":14.0,"high":16.0,"low":13.0,"close":15.0,"volume":200.0}
        ]"#;
        let adapter = JsonAdapter::from_str(json);
        let candles = adapter.candles().unwrap();
        assert_eq!(candles.len(), 2);
        assert_eq!(candles[0].open, 10.0);
        assert_eq!(candles[1].close, 15.0);
    }

    #[test]
    fn parse_points_from_json() {
        let json = r#"[{"x":1.0,"y":2.0},{"x":3.0,"y":4.0}]"#;
        let adapter = JsonAdapter::from_str(json);
        let points = adapter.points().unwrap();
        assert_eq!(points.len(), 2);
        assert_eq!(points[0].x, 1.0);
        assert_eq!(points[1].y, 4.0);
    }

    #[test]
    fn invalid_json_returns_parse_error() {
        let adapter = JsonAdapter::from_str("not json");
        assert!(adapter.candles().is_err());
    }
}
