use tracing::instrument;

use busbar_sf_client::security::soql;

use crate::composite::{
    CompositeBatchRequest, CompositeBatchResponse, CompositeGraphRequest, CompositeGraphResponse,
    CompositeRequest, CompositeResponse, CompositeTreeRequest, CompositeTreeResponse,
};
use crate::error::{Error, ErrorKind, Result};

impl super::SalesforceRestClient {
    /// Execute a composite request with multiple subrequests.
    ///
    /// The composite API allows up to 25 subrequests in a single API call.
    /// Subrequests can reference results from earlier subrequests using `@{referenceId}`.
    ///
    /// Available since API v34.0.
    #[instrument(skip(self, request))]
    pub async fn composite(&self, request: &CompositeRequest) -> Result<CompositeResponse> {
        self.client
            .rest_post("composite", request)
            .await
            .map_err(Into::into)
    }

    /// Execute a composite batch request with multiple independent subrequests.
    ///
    /// The composite batch API executes up to 25 subrequests independently.
    /// Unlike the standard composite API, subrequests cannot reference each other's results.
    ///
    /// Available since API v34.0.
    #[instrument(skip(self, request))]
    pub async fn composite_batch(
        &self,
        request: &CompositeBatchRequest,
    ) -> Result<CompositeBatchResponse> {
        self.client
            .rest_post("composite/batch", request)
            .await
            .map_err(Into::into)
    }

    /// Execute a composite tree request to create record hierarchies.
    ///
    /// Creates parent records with nested child records in a single request.
    /// Supports up to 200 records total across all levels of the hierarchy.
    ///
    /// Available since API v42.0.
    ///
    /// # Arguments
    /// * `sobject` - The parent SObject type (e.g., "Account")
    /// * `request` - The tree request containing parent records and nested children
    #[instrument(skip(self, request))]
    pub async fn composite_tree(
        &self,
        sobject: &str,
        request: &CompositeTreeRequest,
    ) -> Result<CompositeTreeResponse> {
        if !soql::is_safe_sobject_name(sobject) {
            return Err(Error::new(ErrorKind::Salesforce {
                error_code: "INVALID_SOBJECT".to_string(),
                message: "Invalid SObject name".to_string(),
            }));
        }
        let path = format!("composite/tree/{}", sobject);
        self.client
            .rest_post(&path, request)
            .await
            .map_err(Into::into)
    }

    /// Execute a composite graph request with multiple independent graphs.
    ///
    /// Each graph contains a set of composite subrequests that can reference
    /// each other within the same graph. Different graphs are independent.
    ///
    /// Available since API v50.0.
    #[instrument(skip(self, request))]
    pub async fn composite_graph(
        &self,
        request: &CompositeGraphRequest,
    ) -> Result<CompositeGraphResponse> {
        self.client
            .rest_post("composite/graph", request)
            .await
            .map_err(Into::into)
    }
}
