mod cepi;
mod guarded_variable;
mod python;

use std::{collections::HashMap, fs::read_to_string};

use cepi::cepi_22_8::{Cepi22_8, CepiMeta};
use python::PythonObject;

use anyhow::{anyhow, Result};
use chrono::prelude::*;
use clap::Parser;
use rust_database::*;
use serde_json::{from_str, to_string};

use crate::cepi::cepi_22_8::CepiInfo;

/// Helper Program to get Cepi excel files into data base
#[derive(Parser, Debug)]
#[command(version, about)]
struct Args {
    /// Input file (.xlsx)
    #[arg(short, long)]
    file: String,
}

fn main() -> Result<()> {
    let args = Args::parse();

    let file = args.file;

    let cepi_reader = PythonObject::new("../python-cepi-master/cepi_read_function.py")?;

    let cepi_data = cepi_reader.execute_script(
        "read",
        &file,
        |r: HashMap<String, HashMap<String, String>>| Ok(r),
    )?;

    println!("{:#?}", cepi_data);

    if cepi_data.is_empty() {
        return Err(anyhow!("Empty return from python (unsupported version?)"));
    }

    let cepi = Cepi22_8::new(cepi_data, "resources/parameters_Nutzungsrollen.json")?;

    if cepi.version.is_empty() {
        return Err(anyhow!("Could not read cepi file"));
    }

    let cepi_meta = CepiMeta::from(&cepi);
    let meta_str = to_string(&cepi_meta)?;

    let cepi_info = CepiInfo::from(&cepi);
    let info_str = to_string(&cepi_info)?;

    let meta_info = vec![
        ("Gerät", format!("Cepi {}", &cepi.version).as_str()).into(),
        ("MessungsMeta", &meta_str).into(),
        ("MessungsInfo", &info_str).into(),
    ];

    let conf_str = read_to_string("resources/db_config.json")?;
    let config = from_str(&conf_str)?;

    let table_name_str = read_to_string("resources/table_names.json")?;
    let table_names = from_str(&table_name_str)?;

    let mut db = PTSDataBase::new(config, table_names)?;

    // check that the entry is not already in db
    if !db.check_for_infos(&meta_info)? {
        let measurements = cepi.create_measurements();

        let dt = NaiveDateTime::parse_from_str(
            &cepi.uebersicht.probenuntersuchung_datum.value,
            "%Y-%m-%d %H:%M:%S",
        )?;

        let unix_time_stamp = dt.and_utc().timestamp();

        let (config_id, result_id) =
            db.write_measurement(&meta_info, unix_time_stamp, "Ok", &measurements)?;

        println!("Added new entry ({:?}, {:?})", config_id, result_id);
    } else {
        println!("Already in DB!");
    }

    Ok(())
}

#[cfg(test)]
mod test {

    use anyhow::Result;
    use test_case::test_case;

    use crate::python::PythonObject;

    use std::collections::HashMap;

    #[test_case("../laufzettel/CEPI-method_Laufzettel_Part I_V23.07_Ranpak_Muster2.xlsx")]
    fn verify_cepi(file: &str) -> Result<()> {
        let cepi_reader = PythonObject::new("../python-cepi-master/cepi_read_function.py")?;

        let result = cepi_reader.execute_script(
            "read",
            &file,
            |r: HashMap<String, HashMap<String, String>>| Ok(r),
        )?;

        println!("result: {result:#?}");

        Ok(())
    }
}
