// use crate::components::states::MainState;
use crate::transfer::Transfer;
use crate::util::*;

use serde::{Deserialize, Serialize};
use std::error::Error;

#[derive(Serialize, Deserialize, Debug)]
pub struct TransferRecord {
    #[serde(rename = "Source Plate", alias = "source plate", alias = "src plate")]
    pub source_plate: String,
    #[serde(rename = "Source Well", alias = "source well", alias = "src well")]
    pub source_well: String,
    #[serde(
        rename = "Dest Plate",
        alias = "dest plate",
        alias = "destination plate"
    )]
    pub destination_plate: String,
    #[serde(
        rename = "Destination Well",
        alias = "destination well",
        alias = "dest well"
    )]
    pub destination_well: String,
    #[serde(rename = "Transfer Volume", alias = "transfer volume")]
    #[serde(default = "volume_default")]
    pub volume: f32,
    #[serde(rename = "Concentration", alias = "concentration")]
    pub concentration: Option<f32>,
}

pub fn volume_default() -> f32 {
    1f32
}

pub fn transfer_to_records(
    tr: &Transfer,
    src_barcode: &str,
    dest_barcode: &str,
) -> Vec<TransferRecord> {
    let source_wells = tr.transfer_region.get_source_wells();
    let map = tr.transfer_region.calculate_map();

    let mut records: Vec<TransferRecord> = vec![];

    for s_well in source_wells {
        let dest_wells = map(s_well);
        if let Some(dest_wells) = dest_wells {
            for d_well in dest_wells {
                records.push(TransferRecord {
                    source_plate: src_barcode.to_string(),
                    source_well: format!("{}{}", num_to_letters(s_well.0).unwrap(), s_well.1),
                    destination_plate: dest_barcode.to_string(),
                    destination_well: format!("{}{}", num_to_letters(d_well.0).unwrap(), d_well.1),
                    volume: tr.volume,
                    concentration: None,
                })
            }
        }
    }
    records
}

pub fn records_to_csv(trs: Vec<TransferRecord>) -> Result<String, Box<dyn Error>> {
    let mut wtr = csv::WriterBuilder::new().from_writer(vec![]);
    for record in trs {
        wtr.serialize(record)?
    }
    let data = String::from_utf8(wtr.into_inner()?)?;
    Ok(data)
}

pub fn read_csv(data: &str) -> Vec<TransferRecord> {
    let (header, data) = data.split_at(data.find('\n').unwrap());
    let modified: String = header.to_lowercase() + data;

    let mut rdr = csv::Reader::from_reader(modified.as_bytes());
    let mut records: Vec<TransferRecord> = Vec::new();
    for record in rdr.deserialize::<TransferRecord>() {
        match record {
            Ok(r) => {
                //log::debug!("{:?}", r);
                records.push(r);
            }
            Err(e) => {
                log::debug!("{:?}", e);
            }
        }
    }
    records
}
