use std::net::SocketAddrV4;
use reqwest::header::{HeaderValue, CONTENT_TYPE};
use warp::Filter;
use crate::model::Model;

// Recieve config from front end
// send config to all RTUs, get it back
// send it back to front end

// Send given model to RTU at given address and returns the updated model.
// This will be called for each RTU.
fn update(current_model: &Model, addr: SocketAddrV4) -> Model {
    let client = reqwest::blocking::Client::new();
    let body = client
        .post(&format!("http://{}/model", addr))
        .body(serde_json::to_string(current_model).expect("Couldn't deserialize model"))
        .header(CONTENT_TYPE, HeaderValue::from_static("application/json"))
        .send()
        .expect("Something went wrong, could not post to RTU");

    // ...and update current_model with whatever is returned
    let err_msg = format!("Could not get model back from RTU with address {}", addr);
    // Do NOT read body.json() or body.text() before this line, it only works once because crackheads i guess
    // Note: future luke (mildly smarter) knows that calling .text() consumes the body
    serde_json::from_str(&body.text().unwrap()).expect(&err_msg)
}

pub async fn run() {
    let running = warp::path("running").map(|| r#"{"running":"true"}"# );
    
    let config_dep = warp::path("configuration")
        .map(|| {
            "deprecated"
        });

    let handle_model = warp::path("model")
        .and(warp::body::json())
        .map(|model: Model| {
            println!("Master API recieved a model, about to send it to the RTUs");
            let addrs: Vec<SocketAddrV4> = model
                .RTUs
                .iter()
                .map(|rtu| rtu.ipv4 )
                .collect();

            let mut current_model = model;
            for addr in addrs {
                current_model = update(&current_model, addr);
            }
            
            serde_json::to_string(&current_model).expect("Couldn't serialize model")
        });

    let routes = running
        .or(config_dep)
        .or(handle_model);

        warp::serve(routes)
            .run(([0, 0, 0, 0], 8000))
            .await;
}