// Copyright 2023 Salesforce, Inc. All rights reserved.
use std::fmt::Display;

use anyhow::anyhow;
use serde::Serialize;

use crate::api::metadata::PolicyMetadata;
use crate::api::{FlexAbi, FlexAbiImpl};
use crate::hostcalls;
use crate::hostcalls::FlexLogLevel;

pub fn wrap_entrypoint<O, E>(entrypoint: fn(&dyn FlexAbi) -> Result<O, E>) -> bool
where
    O: Serialize,
    E: Display,
{
    match do_wrap_entrypoint(entrypoint) {
        Ok(_) => true,
        Err(e) => {
            let casted: anyhow::Error = e;
            hostcalls::log(
                FlexLogLevel::Error,
                format!("Error initializing policy: {casted}").as_str(),
            );
            false
        }
    }
}

fn do_wrap_entrypoint<O, E>(
    entrypoint: fn(&dyn FlexAbi) -> Result<O, E>,
) -> Result<(), anyhow::Error>
where
    O: Serialize,
    E: Display,
{
    let config = hostcalls::get_configuration()?.unwrap_or_default();
    let metadata_bytes = hostcalls::get_metadata()?.unwrap_or_default();
    let metadata: PolicyMetadata = serde_json::from_slice(&metadata_bytes).unwrap();
    let abi: &dyn FlexAbi = &FlexAbiImpl { metadata, config };

    entrypoint(abi).map_err(|e| anyhow!(format!("{e}")))?;

    Ok(())
}
