use cw_client::{CliClient, CwClient};
use mc_attestation_verifier::SignedTcbInfo;
use p256::ecdsa::VerifyingKey;
use quartz_tcbinfo_msgs::ExecuteMsg;
use quoted_string::strip_dquotes;
use reqwest::Url;
use serde_json::{json, Value};


type Fmspc = String;
type Update = String;

const TCB_SIGNER: &str = include_str!("../tcb_signer.pem");

async fn get_tcbinfo(fmspc: Fmspc, update: Update) -> String {
    let url = format!("https://api.trustedservices.intel.com/sgx/certification/v4/tcb?fmspc={fmspc}&update={update}");
    let body: String = reqwest::get(url)
        .await
        .expect("url retrieval failed")
        .text()
        .await
        .expect("could not read https response");
    body
}

async fn get_fmspc_list() -> Vec<Fmspc> {
    let body: String =
        reqwest::get("https://api.trustedservices.intel.com/sgx/certification/v4/fmspcs")
            .await
            .expect("url retrieval failed")
            .text()
            .await
            .expect("could not read https response");
    let fmspc_data: Vec<Value> = serde_json::from_str(&body).expect("could not convert to JSON");
    let mut fmspc_list: Vec<Fmspc> = Vec::new();
    for item in fmspc_data.iter() {
        let fmspc: String = format!("{}", item["fmspc"]);
        fmspc_list.push(strip_dquotes(&fmspc).unwrap().to_string());
    }
    println!("{:?}", fmspc_list);
    fmspc_list
}

async fn upsert_tcbinfo() -> Result<(), &'static str> {

    let testnet = Url::parse("https://rpc-falcron.pion-1.ntrn.tech").expect("couldn't parse network URL");
           
    let client = CliClient::neutrond(testnet);
    let fmspc_list = get_fmspc_list().await;

    for fmspc in fmspc_list {
        
        let tcbinfo_from_api = get_tcbinfo(fmspc.clone(), "standard".to_string()).await;
        // assert!(verify_signature(tcbinfo.clone(), key));
         let contract_address =
                "neutron1r4m59786vmxrx866585ze5ugjx9egcyja0nuxhn2y6d7ht6680sspa89zk"
                    .parse()
            .expect("failed to parse contract address");
        let query_msg = format!("{{\"get_tcb_info\": {{\"fmspc\": \"{}\"}}}}", fmspc) ;
        let tcbinfo_on_chain: Value =  client.query_smart(&contract_address, json!(query_msg)).await.expect("contract query failed");
        println!("{tcbinfo_on_chain:?}");
      
        if tcbinfo_on_chain.to_string() != tcbinfo_from_api {
            println!("updating on-chain TCBInfo for FMSPC: {fmspc}");
            let chain_id = tendermint::chain::id::Id::try_from("pion-1").expect("invalid chain id");
            let sender = "ajinkya";
           
            let execute_msg = ExecuteMsg {
                tcb_info: tcbinfo_from_api.to_string(),
                certificate: TCB_SIGNER.to_string(),
                time: None,
            };
            let _ = client
                .tx_execute(
                    &contract_address,
                    &chain_id,
                    1000000,
                    sender,
                    json!(execute_msg),
                    "11000untrn",
                )
                .await;
            println!("done");
            std::thread::sleep(std::time::Duration::from_secs(5));
        } else {
            println!("TCBInfo for FMSPC: {fmspc} up to date")
        }
    }
    Ok(())
}



#[tokio::main]
pub async fn main() {
    upsert_tcbinfo().await.expect("TCBInfo update failed");
}