//! Low-level utilities for interacting with services.

use anyhow::anyhow;
use bytes::Bytes;
use jam_program_blob_common::{read_metadata, ConventionalMetadata};
use jam_std_common::{Node, NodeExt as _, Service};
use jam_types::{HeaderHash, ServiceId};

const JAM_TOOL_VERSION: &str = env!("CARGO_PKG_VERSION");

/// Queries the service and ensures that it has specified crate name in the metadata.
///
/// Returns [`Service`] and code blob.
///
/// Logs a warning on the version mismatch.
pub async fn query(
	node: &dyn Node,
	head: HeaderHash,
	service_id: ServiceId,
	crate_name: &str,
) -> anyhow::Result<(Service, Bytes)> {
	let service = node
		.service_data(head, service_id)
		.await?
		.ok_or_else(|| anyhow!("Service {service_id:x} not found"))?;
	let code = node
		.service_preimage(head, service_id, service.code_hash.0)
		.await?
		.ok_or_else(|| anyhow!("Code for service {service_id:x} is not provided"))?;
	match read_metadata(&mut &code[..]) {
		Ok(ConventionalMetadata::Info(crate_info)) if crate_info.name == crate_name => {
			if crate_info.version != JAM_TOOL_VERSION {
				log::warn!(
					"{crate_name}-{} service might be incompatible with jamt-{JAM_TOOL_VERSION}",
					crate_info.version,
				);
			}
			Ok((service, code))
		},
		_ => Err(anyhow!("Service {service_id:x} does not appear to be {crate_name:?}")),
	}
}
