use serde_json::{self, Value};
use hyper::http::HeaderValue;
use hyper::Response;
use hyper::Body;
use hyper::body::to_bytes;

use std::u8;
use std::collections::HashMap;

const APP_JSON_HEADER: &'static str = "application/json";
const CONTENT_TYPE: &'static str = "Content-Type";

pub fn set_json_body(response: &mut Response<Body>, values: Value) {
    response.headers_mut().insert(
        CONTENT_TYPE, 
        HeaderValue::from_static(APP_JSON_HEADER));
    
    *response.body_mut() = Body::from(values.to_string());
}

pub async fn parse_json_params(body_raw: &mut Body) -> Result<Value, serde_json::error::Error> {
    let bytes: &[u8] = &*to_bytes(body_raw).await.unwrap(); // rarely fails 
    let values: Value;
    if bytes.len() == 0 {
        values = serde_json::from_str("{}")?;
    }
    else {
        values = serde_json::from_slice(bytes)?;
    }
    Ok(values)
}

pub fn parse_query_string<'qs>(string: &'qs str) 
        -> HashMap<&str, &str> {
    
    let mut map: HashMap<&str, &str> = HashMap::new();

    // get pairs of [key1=value1, key2=value2, ...]
    for pair in string.split('&') {

        let kv: Vec<&str> = pair.split('=').collect();

        match (kv.get(0), kv.get(1)) {
            // only if the format is some_key=some_value do we actually care about it
            (Some(key), Some(value)) => {
                map.insert(key, value);
            },
            // ignore all non-pairs
            _ => continue
        };
    }
    return map;
}

#[inline]
pub fn extract_uid(values: &HashMap<&str, &str>) -> u64 {
    // NOTE: this is only to be used _AFTER_ the auth module passes since it
    // guarantees the id is verified
    let map = *values;
    let val = *map.get("id").unwrap();
    let s: String = String::from(val);
    return s.parse::<u64>().unwrap();
}
