use std::fs::File;
use std::io::{ Write, Read };
use serde::{ Deserialize, Serialize };
use ring::{
    signature::{ KeyPair, Ed25519KeyPair, UnparsedPublicKey, ED25519 },
    rand,
    // hmac, digest, error::Unspecified,
};
use rust_util::XResult;

#[derive(Clone, Serialize, Deserialize)]
pub struct SigningKeyPair {
    key_pair: Vec<u8>,
}

impl SigningKeyPair {
    pub fn new() -> Self {
        let rng = rand::SystemRandom::new();
        let pkcs8 = Ed25519KeyPair::generate_pkcs8(&rng).unwrap(); //  TODO ...
        SigningKeyPair{
            key_pair: pkcs8.as_ref().to_vec(),
        }
    }

    pub fn key_pair(&self) -> Ed25519KeyPair {
        Ed25519KeyPair::from_pkcs8(&self.key_pair).unwrap() // TODO ...
    }

    pub fn public_key(&self) -> Vec<u8> {
        self.key_pair().public_key().as_ref().to_vec()
    }

    pub fn unparsed_public_key(&self) -> UnparsedPublicKey<Vec<u8>> {
        UnparsedPublicKey::new(&ED25519, self.public_key())
    }

    pub fn read_from_file(file: &str) -> XResult<Self> {
        match File::open(file) {
            Err(e) => Err(rust_util::new_box_ioerror(&format!("Read from file failed: {}", e))),
            Ok(mut f) => {
                let mut buf = String::new();
                match f.read_to_string(&mut buf) {
                    Err(e) => Err(rust_util::new_box_ioerror(&format!("Read from file failed: {}", e))),
                    Ok(_) => {
                        let kp: Self = match serde_json::from_str(&buf) {
                            Err(e) => return Err(rust_util::new_box_ioerror(&format!("Parse JSON failed: {}", e))),
                            Ok(k) => k,
                        };
                        Ok(kp)
                    }
                }
            },
        }
    }

    pub fn write_to_file(&self, file: &str) -> XResult<()> {
        if File::open(file).is_ok() {
            return Err(rust_util::new_box_ioerror(&format!("File exists: {}", file)));
        }
        let ser_bytes = match serde_json::to_string_pretty(self) {
            Err(e) => return  Err(rust_util::new_box_ioerror(&format!("Serilize key pair failed: {}", e))),
            Ok(s) => s,
        };
        match File::create(file) {
            Err(e) => Err(rust_util::new_box_ioerror(&format!("File create: {}, failed: {}", file, e))),
            Ok(mut f) => {
                match f.write_all(ser_bytes.as_bytes()) {
                    Err(e) => Err(rust_util::new_box_ioerror(&format!("File create: {}, failed: {}", file, e))),
                    Ok(_) => Ok(()),
                }
            },
        }
    }
}

#[derive(Serialize, Deserialize)]
pub struct SignedMessage {
    pub msg: Vec<u8>,
    pub sig: Option<Vec<u8>>,
    pub desc: Option<String>,
}

impl SignedMessage {
    pub fn new(msg: Vec<u8>, desc: Option<String>) -> Self {
        Self {
            msg,
            sig: None,
            desc,
        }
    }

    pub fn sign(&mut self, key_pair: &SigningKeyPair) {
        let sig = key_pair.key_pair().sign(&self.msg);
        self.sig = Some(sig.as_ref().to_vec());
    }

    pub fn verify(&self, public_key: &[u8]) -> bool {
        match &self.sig {
            None => false,
            Some(sig) => {
                let verify_result = UnparsedPublicKey::new(&ED25519, &public_key).verify(&self.msg, sig);
                verify_result.is_ok()
            }
        }
    }
}

#[test]
fn test_sign() {
    let signing_key_pair = SigningKeyPair::new();
    let mut signed_message = SignedMessage::new(
        "Hello".as_bytes().to_vec(), Some("DESC".to_owned())
    );
    signed_message.sign(&signing_key_pair);
    assert!(signed_message.verify(&signing_key_pair.public_key()))
}
