use std::io::Write;

use log::{debug, info};

use crate::IInstr;

#[derive(Default, Debug)]
pub struct CurrentData {
    pub avgCurr: f64,
    pub highCuur: f64,
    pub lowCurr: f64,
    pub maxCurr: f64,
    pub minCurr: f64,
}
impl CurrentData {
    pub fn new() -> Self {
        Self {
            ..Default::default()
        }
    }
    pub fn to_tb(&self) -> String {
        format!(
            "{},{},{},{},{}",
            self.avgCurr, self.maxCurr, self.minCurr, self.highCuur, self.lowCurr
        )
    }
}
impl std::fmt::Display for CurrentData {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "avg:{}, max:{}, min:{} ,high:{} ,low:{}",
            self.avgCurr, self.maxCurr, self.minCurr, self.highCuur, self.lowCurr
        )
    }
}

pub struct P66319D {
    pub instr: visa_rs::Instrument,
    pub datafile: Option<std::fs::File>,
}

impl P66319D {
    pub fn new(instr: visa_rs::Instrument) -> Self {
        Self {
            instr,
            datafile: None,
        }
    }
    pub fn m_init(&mut self) -> std::io::Result<()> {
        self.instr.m_send("*RST; *OPC?")
    }
    /// channel 1|2 ,volt v
    pub fn m_set_volt(&mut self, channel: u64, volt: f64) -> std::io::Result<()> {
        self.instr
            .m_send(&format!("SOUR{}:VOLT {:.2}", channel, volt))
    }
    /// channel 1|2 ,en e
    pub fn m_set_poweron(&mut self, channel: u64, on: bool) -> std::io::Result<()> {
        self.instr.m_send(&format!(
            "OUTP{} {}",
            channel,
            if on { "ON" } else { "OFF" }
        ))
    }

    pub fn m_set_test_accur(&mut self, accur: &str) -> std::io::Result<()> {
        match accur {
            "100.us/div" => self
                .instr
                .m_send("SENS:SWE:TINT 1.56E-005;POIN 38;OFFS:POIN 0"),
            "200.us/div" => self
                .instr
                .m_send("SENS:SWE:TINT 1.56E-005;POIN 76;OFFS:POIN 0"),
            "500.us/div" => self
                .instr
                .m_send("SENS:SWE:TINT 1.56E-005;POIN 192;OFFS:POIN 0"),
            "1.ms/div" => self
                .instr
                .m_send("SENS:SWE:TINT 1.56E-005;POIN 384;OFFS:POIN 0"),
            "2.ms/div" => self
                .instr
                .m_send("SENS:SWE:TINT 1.56E-005;POIN 769;OFFS:POIN 0"),
            "5.ms/div" => self
                .instr
                .m_send("SENS:SWE:TINT 1.56E-005;POIN 1923;OFFS:POIN 0"),
            "10.ms/div" => self
                .instr
                .m_send("SENS:SWE:TINT 1.56E-005;POIN 3846;OFFS:POIN 0"),
            "20.ms/div" => self
                .instr
                .m_send("SENS:SWE:TINT 3.12E-005;POIN 3846;OFFS:POIN 0"),
            "50.ms/div" => self
                .instr
                .m_send("SENS:SWE:TINT 7.8E-005;POIN 3846;OFFS:POIN 0"),
            "100.ms/div" => self
                .instr
                .m_send("SENS:SWE:TINT 0.000156;POIN 3846;OFFS:POIN 0"),
            "200.ms/div" => self
                .instr
                .m_send("SENS:SWE:TINT 0.0002964;POIN 4048;OFFS:POIN 0"),
            "500.ms/div" => self
                .instr
                .m_send("SENS:SWE:TINT 0.0007332;POIN 4091;OFFS:POIN 0"),
            "1.s/div" => self
                .instr
                .m_send("SENS:SWE:TINT 0.0014664;POIN 4091;OFFS:POIN 0"),
            "2.s/div" => self
                .instr
                .m_send("SENS:SWE:TINT 0.0029328;POIN 4091;OFFS:POIN 0"),
            "4.s/div" => self
                .instr
                .m_send("SENS:SWE:TINT 0.0058656;POIN 4091;OFFS:POIN 0"),

            _ => Err(std::io::Error::from_raw_os_error(233)),
        }
    }
    pub fn m_set_ps_mode(&mut self, mode: bool) -> std::io::Result<()> {
        self.instr.m_send(&format!(
            "OUTP:COMP:MODE {}",
            if mode { "HLOCAL" } else { "LLOCAL" }
        ))?;
        self.instr
            .m_send("SENS:SWE:TINT 0.0001;POIN 512;OFFS:POIN 0")
    }
    pub fn m_measure_current(&mut self) -> Option<CurrentData> {
        let mut curdata = CurrentData::new();
        self.read_esr_state();
        let ss = self.instr.m_query("MEAS:ARR:CURR?")?;
        let mut data = Vec::new();
        debug!("{ss}");
        if let Some(dfile) = &mut self.datafile {
            dfile.write(ss.as_bytes());
        }
        for idx in ss.trim().split(",") {
            match idx.parse::<f64>() {
                Ok(vl) => {
                    data.push(vl);
                }
                Err(_) => {}
            }
        }

        debug!("count:{}", data.len());
        debug!("avgcurr:{}", data.iter().sum::<f64>() / data.len() as f64);

        self.read_esr_state();
        let ss = self.instr.m_query("FETC:CURR?")?;
        let ss_v = ss.trim().parse::<f64>().ok()?;
        curdata.avgCurr = ss_v;
        self.read_esr_state();
        let ss = self.instr.m_query("FETC:CURR:MAX?")?;
        let ss_v = ss.trim().parse::<f64>().ok()?;
        curdata.maxCurr = ss_v;
        self.read_esr_state();
        let ss = self.instr.m_query("FETC:CURR:MIN?")?;
        let ss_v = ss.trim().parse::<f64>().ok()?;
        curdata.minCurr = ss_v;
        self.read_esr_state();
        let ss = self.instr.m_query("FETC:CURR:HIGH?")?;
        let ss_v = ss.trim().parse::<f64>().ok()?;
        curdata.highCuur = ss_v;
        self.read_esr_state();
        let ss = self.instr.m_query("FETC:CURR:LOW?")?;
        let ss_v = ss.trim().parse::<f64>().ok()?;
        curdata.lowCurr = ss_v;
        self.read_esr_state();

        Some(curdata)
    }
    fn read_esr_state(&mut self) {
        loop {
            if let Some(ss) = self.instr.m_query("*ESR?") {
                if let Some(_) = ss.find("+0") {
                    break;
                }
            }
        }
    }
}
