use serde::{Serialize, Deserialize};
use rust_util::XResult;
use crate::credit::CreditContract;
use crate::credit_util::{save_credit_contract, load_credit_contract};
use crate::tx::{Transaction, TransactionBody};

#[derive(Debug, Serialize, Deserialize)]
pub struct CreditContractCreateParameters {
    pub name: String,
    pub credit_limit: u32,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct CreditContractIssueParameters {
    pub name: String,
    pub receiver: String,
    pub credit: u32,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct CreditContractTransferParameters {
    pub name: String,
    pub receiver: String,
    pub credit: u32,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct CreditContractQueryParameters {
    pub name: String,
    pub account: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct CreditContractQueryAllParameters {
    pub name: String,
}

pub struct ContractEngineCredit {
}

impl ContractEngineCredit {
    pub fn new() -> Self {
        Self{}
    }

    pub fn execute(&self, tx: &Transaction, tx_body: &TransactionBody) -> XResult<()> {
        let action = tx_body.action.as_str();

        debugging!("Creidt contract, action: {}", action);
        match action {
            "create" => {
                let params: CreditContractCreateParameters = serde_json::from_str(&tx_body.parameters)?;
                let c = CreditContract::new(tx, &params.name, params.credit_limit)?;
                save_credit_contract(&c, false)?;
            },
            "issue" => {
                let params: CreditContractIssueParameters = serde_json::from_str(&tx_body.parameters)?;
                let mut c = load_credit_contract(&params.name)?;
                c.issue(tx, &params.receiver, params.credit)?;
                save_credit_contract(&c, true)?;
            },
            "transfer" => {
                let params: CreditContractTransferParameters = serde_json::from_str(&tx_body.parameters)?;
                let mut c =load_credit_contract(&params.name)?;
                c.transfer(tx, &params.receiver, params.credit)?;
                save_credit_contract(&c, true)?;
            },
            "query" => {
                let params: CreditContractQueryParameters = serde_json::from_str(&tx_body.parameters)?;
                let c = load_credit_contract(&params.name)?;
                success!("Query: {}, credit: {}", &params.account, c.query(tx, &params.account));
            },
            "query_all" => {
                let params: CreditContractQueryAllParameters = serde_json::from_str(&tx_body.parameters)?;
                let c = load_credit_contract(&params.name)?;
                let map = c.query_all(tx);
                map.iter().for_each(|(k , v)| {
                    success!("Query: {}, credit: {}", k, v);
                });
            },
            _ => return simple_error!("Unknown action: {}", action),
        }
        Ok(())
    }
}
