// Code generated by software.amazon.smithy.rust.codegen.smithy-rs. DO NOT EDIT.
/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

#![allow(dead_code)]

use crate::presigning::{PresigningConfig, PresigningMarker};
use crate::serialization_settings::HeaderSerializationSettings;
use aws_runtime::auth::{HttpSignatureType, SigV4OperationSigningConfig};
use aws_runtime::invocation_id::InvocationIdInterceptor;
use aws_runtime::request_info::RequestInfoInterceptor;
use aws_runtime::user_agent::UserAgentInterceptor;
use aws_sigv4::http_request::SignableBody;
use aws_smithy_async::time::{SharedTimeSource, StaticTimeSource};
use aws_smithy_runtime::client::retries::strategy::NeverRetryStrategy;
use aws_smithy_runtime_api::box_error::BoxError;
use aws_smithy_runtime_api::client::interceptors::context::{BeforeSerializationInterceptorContextMut, BeforeTransmitInterceptorContextMut};
use aws_smithy_runtime_api::client::interceptors::{disable_interceptor, Intercept, SharedInterceptor};
use aws_smithy_runtime_api::client::retries::SharedRetryStrategy;
use aws_smithy_runtime_api::client::runtime_components::{RuntimeComponents, RuntimeComponentsBuilder};
use aws_smithy_runtime_api::client::runtime_plugin::RuntimePlugin;
use aws_smithy_types::config_bag::{ConfigBag, FrozenLayer, Layer};
use std::borrow::Cow;

/// Interceptor that tells the SigV4 signer to add the signature to query params,
/// and sets the request expiration time from the presigning config.
#[derive(Debug)]
pub(crate) struct SigV4PresigningInterceptor {
    config: PresigningConfig,
    payload_override: SignableBody<'static>,
}

impl SigV4PresigningInterceptor {
    pub(crate) fn new(config: PresigningConfig, payload_override: SignableBody<'static>) -> Self {
        Self { config, payload_override }
    }
}

impl Intercept for SigV4PresigningInterceptor {
    fn name(&self) -> &'static str {
        "SigV4PresigningInterceptor"
    }

    fn modify_before_serialization(
        &self,
        _context: &mut BeforeSerializationInterceptorContextMut<'_>,
        _runtime_components: &RuntimeComponents,
        cfg: &mut ConfigBag,
    ) -> Result<(), BoxError> {
        cfg.interceptor_state().store_put::<HeaderSerializationSettings>(
            HeaderSerializationSettings::new()
                .omit_default_content_length()
                .omit_default_content_type(),
        );

        cfg.interceptor_state().store_put(PresigningMarker);
        Ok(())
    }

    fn modify_before_signing(
        &self,
        _context: &mut BeforeTransmitInterceptorContextMut<'_>,
        _runtime_components: &RuntimeComponents,
        cfg: &mut ConfigBag,
    ) -> Result<(), BoxError> {
        if let Some(mut config) = cfg.load::<SigV4OperationSigningConfig>().cloned() {
            config.signing_options.expires_in = Some(self.config.expires());
            config.signing_options.signature_type = HttpSignatureType::HttpRequestQueryParams;
            config.signing_options.payload_override = Some(self.payload_override.clone());
            cfg.interceptor_state().store_put::<SigV4OperationSigningConfig>(config);
            Ok(())
        } else {
            Err("SigV4 presigning requires the SigV4OperationSigningConfig to be in the config bag. \
                This is a bug. Please file an issue."
                .into())
        }
    }
}

/// Runtime plugin that registers the SigV4PresigningInterceptor.
#[derive(Debug)]
pub(crate) struct SigV4PresigningRuntimePlugin {
    runtime_components: RuntimeComponentsBuilder,
}

impl SigV4PresigningRuntimePlugin {
    pub(crate) fn new(config: PresigningConfig, payload_override: SignableBody<'static>) -> Self {
        let time_source = SharedTimeSource::new(StaticTimeSource::new(config.start_time()));
        Self {
            runtime_components: RuntimeComponentsBuilder::new("SigV4PresigningRuntimePlugin")
                .with_interceptor(SharedInterceptor::new(SigV4PresigningInterceptor::new(config, payload_override)))
                .with_retry_strategy(Some(SharedRetryStrategy::new(NeverRetryStrategy::new())))
                .with_time_source(Some(time_source)),
        }
    }
}

impl RuntimePlugin for SigV4PresigningRuntimePlugin {
    fn config(&self) -> Option<FrozenLayer> {
        let mut layer = Layer::new("Presigning");
        layer.store_put(disable_interceptor::<InvocationIdInterceptor>("presigning"));
        layer.store_put(disable_interceptor::<RequestInfoInterceptor>("presigning"));
        layer.store_put(disable_interceptor::<UserAgentInterceptor>("presigning"));
        Some(layer.freeze())
    }

    fn runtime_components(&self, _: &RuntimeComponentsBuilder) -> Cow<'_, RuntimeComponentsBuilder> {
        Cow::Borrowed(&self.runtime_components)
    }
}
