use std::fs::File;

use serde::de::DeserializeOwned;

use crate::IResult;

/// 以csv 格式保存数据, 第1行为标题, 第2行为数据; 以逗号分隔; 写入serde::Ser数据, 取对象的key为标题, 取对象的value为数据
/// 读取数据时, 以第1行为标题, 读取第2行开始的数据
/// 读取数据格式, 每一行数据以标题为key, 反序列化为serde::Deser; 多行数据保存为vector
pub fn save<T: serde::Serialize>(arr: Vec<T>, path: &str) -> Result<(), Box<dyn std::error::Error>> {
    let mut wtr = csv::Writer::from_path(path)?;
    for item in arr {
        wtr.serialize(item)?;
    }
    wtr.flush()?;
    Ok(())
}

pub struct CsvHander {
    file: csv::Writer<File>,
}

impl CsvHander {
    pub fn new(path: &str) -> IResult<Self> {
        debug!("csv_util::CsvHander::new: {}", path);
        let file = std::fs::File::options().create_new(true).append(true).open(path)?;
        let wtr: csv::Writer<File> = csv::WriterBuilder::new().has_headers(true).from_writer(file);
        let r = Self { file: wtr };
        Ok(r)
    }

    /// 以csv 格式保存数据, 第1行为标题, 第2行为数据; 以逗号分隔; 写入serde::Ser数据, 取对象的key为标题, 取对象的value为数据
    /// 读取数据时, 以第1行为标题, 读取第2行开始的数据
    /// 读取数据格式, 每一行数据以标题为key, 反序列化为serde::Deser; 多行数据保存为vector
    pub fn save_append<T: serde::Serialize>(&mut self, arr: Vec<T>) -> IResult<()> {
        for item in arr {
            self.file.serialize(item)?;
        }
        self.file.flush()?;
        Ok(())
    }
}

pub fn read<R: DeserializeOwned>(path: &str) -> Result<Vec<R>, Box<dyn std::error::Error>> {
    let mut rdr = csv::Reader::from_path(path)?;
    let mut data = vec![];
    let iter: csv::DeserializeRecordsIter<'_, std::fs::File, R> = rdr.deserialize();
    for (i, row) in iter.into_iter().enumerate() {
        let row = match row {
            Ok(row) => row,
            Err(e) => {
                let i = i + 1;
                error!("read csv {path}:{i} error: {}", e);
                continue;
            }
        };
        data.push(row);
    }
    Ok(data)
}

#[test]
fn test_csv() {
    #[derive(Debug, serde::Serialize, serde::Deserialize)]
    struct Test {
        name: String,
        age: i32,
    }
    let data = vec![
        Test { name: "张三".to_string(), age: 18 },
        Test { name: "李四".to_string(), age: 20 },
        Test { name: "3".to_string(), age: 35 },
    ];
    let path = "test2.csv";
    save(data, path).unwrap();
    let data: Vec<Test> = read(path).unwrap();
    println!("read: {:?}", data);

    assert_eq!(data[0].name, "张三");
    assert_eq!(data[1].name, "李四");
}

#[test]
fn test_csv_hander() {
    #[derive(Debug, serde::Serialize, serde::Deserialize)]
    struct Test {
        name: String,
        age: i32,
    }
    let path = "test2.csv";
    let mut handler = CsvHander::new(path).unwrap();
    let data = vec![
        Test { name: "张三".to_string(), age: 18 },
    ];
    handler.save_append(data).unwrap();
    handler.save_append(vec![
        Test { name: "李四".to_string(), age: 20 },
        Test { name: "3".to_string(), age: 35 },
    ]).unwrap();
    assert_eq!(read::<Test>(path).unwrap()[0].name, "张三");
    assert_eq!(read::<Test>(path).unwrap()[1].name, "李四");
}