// Code generated by software.amazon.smithy.rust.codegen.smithy-rs. DO NOT EDIT.
use crate::client::Handle;
pub use aws_smithy_http::operation::Operation;
pub use aws_smithy_http::retry::ClassifyRetry;
pub use aws_smithy_types::retry::RetryKind;

use aws_smithy_http::body::SdkBody;
use aws_smithy_http::result::SdkError;

use std::convert::Infallible;
use std::sync::Arc;

/// A wrapper type for [`Operation`](aws_smithy_http::operation::Operation)s that allows for
/// customization of the operation before it is sent. A `CustomizableOperation` may be sent
/// by calling its [`.send()`][crate::operation::customize::CustomizableOperation::send] method.
#[derive(Debug)]
pub struct CustomizableOperation<O, Retry> {
    pub(crate) handle: Arc<Handle>,
    pub(crate) operation: Operation<O, Retry>,
}

impl<O, Retry> CustomizableOperation<O, Retry> {
    /// Allows for customizing the operation's request
    pub fn map_request<E>(
        mut self,
        f: impl FnOnce(http::Request<SdkBody>) -> Result<http::Request<SdkBody>, E>,
    ) -> Result<Self, E> {
        let (request, response) = self.operation.into_request_response();
        let request = request.augment(|req, _props| f(req))?;
        self.operation = Operation::from_parts(request, response);
        Ok(self)
    }

    /// Convenience for `map_request` where infallible direct mutation of request is acceptable
    pub fn mutate_request(self, f: impl FnOnce(&mut http::Request<SdkBody>)) -> Self {
        self.map_request(|mut req| {
            f(&mut req);
            Result::<_, Infallible>::Ok(req)
        })
        .expect("infallible")
    }

    /// Allows for customizing the entire operation
    pub fn map_operation<E>(
        mut self,
        f: impl FnOnce(Operation<O, Retry>) -> Result<Operation<O, Retry>, E>,
    ) -> Result<Self, E> {
        self.operation = f(self.operation)?;
        Ok(self)
    }

    /// Direct access to read the HTTP request
    pub fn request(&self) -> &http::Request<SdkBody> {
        self.operation.request()
    }

    /// Direct access to mutate the HTTP request
    pub fn request_mut(&mut self) -> &mut http::Request<SdkBody> {
        self.operation.request_mut()
    }
}

impl<O, Retry> CustomizableOperation<O, Retry> {
    /// Sends this operation's request
    pub async fn send<T, E>(self) -> Result<T, SdkError<E>>
    where
        E: std::error::Error + Send + Sync + 'static,
        O: aws_smithy_http::response::ParseHttpResponse<Output = Result<T, E>>
            + Send
            + Sync
            + Clone
            + 'static,
        Retry: aws_smithy_http::retry::ClassifyRetry<
                aws_smithy_http::result::SdkSuccess<T>,
                SdkError<E>,
            > + Send
            + Sync
            + Clone,
    {
        self.handle.client.call(self.operation).await
    }
}
