use std::fs::File;
use std::io::Read;
use serde::{ Serialize, Deserialize };
use crate::sig::SigningKeyPair;
use rust_util::XResult;

lazy_static::lazy_static! {
    static ref SIGNING_KEY_PAIR: Option<SigningKeyPair> = load_signing_key_pair_ok();
}

#[derive(Serialize, Deserialize, Default)]
pub struct HttpResult {
    pub status: u16,
    pub message: String,
    pub result: Option<String>,
    pub js_hash: Option<String>,
}

impl HttpResult {
    pub fn new() -> Self {
        Self { ..Default::default() }
    }
    pub fn new_200(message: String, result: Option<String>) -> Self {
        Self {
            status: 200,
            message,
            result,
            ..Default::default()
        }
    }
    pub fn new_400(message: String, result: Option<String>) -> Self {
        Self {
            status: 400,
            message,
            result,
            ..Default::default()
        }
    }
    pub fn new_500(message: String, result: Option<String>) -> Self {
        Self {
            status: 200,
            message,
            result,
            ..Default::default()
        }
    }
    pub fn status(&mut self, status: u16) -> &mut Self {
        self.status = status;
        self
    }
    pub fn message(&mut self, message: String) -> &mut Self {
        self.message = message;
        self
    }
    pub fn result(&mut self, result: String) -> &mut Self {
        self.result = Some(result);
        self
    }
    pub fn js_hash(&mut self, js_hash: String) -> &mut Self {
        self.js_hash = Some(js_hash);
        self
    }
    pub fn to_string(&self) -> String {
        serde_json::to_string(&self).map(|mut s| { s.push('\n'); s }).unwrap_or_else(|e| format!("HttpResult to JSON failed: {}", e))
    }
    pub fn to_string_pretty(&self) -> String {
        serde_json::to_string_pretty(&self).map(|mut s| { s.push('\n'); s }).unwrap_or_else(|e| format!("HttpResult to JSON failed: {}", e))
    }
}

pub fn get_signing_public_key() -> Option<String> {
    SIGNING_KEY_PAIR.as_ref().map(|key_pair| hex::encode(&key_pair.public_key()))
}

pub fn load_signing_key_pair() -> XResult<SigningKeyPair> {
    SigningKeyPair::read_from_file("platform_signing_key.json")
}

pub fn load_signing_key_pair_ok() -> Option<SigningKeyPair> {
    load_signing_key_pair().ok()
}

pub fn read_file(f: &str) -> XResult<String> {
    let mut file = File::open(&f).map_err(|e| rust_util::new_box_error(&format!("Open file: {}, failed: {}", f , e)))?;
    let mut buf = String::new();
    file.read_to_string(&mut buf).map_err(|e| rust_util::new_box_error(&format!("Read file: {}, failed: {}", f , e)))?;
    Ok(buf)
}