//! Arc-shareable wrapper around `S4Service<B>` (v0.7 #45).
//!
//! Background: the v0.7 #45 lifecycle scanner needs an `Arc<S4Service<B>>`
//! handle so a long-running tokio task can call `list_objects_v2` /
//! `head_object` / `delete_object` against the same service the hyper
//! listener is serving. The s3s framework's
//! [`s3s::service::S3ServiceBuilder::new`] takes `s3: impl S3` by value
//! (and internally wraps in `Arc::new`), so a plain `Arc<S4Service<B>>`
//! cannot be passed directly — the trait bound `Arc<S4Service<B>>: S3`
//! is not satisfied automatically.
//!
//! This module provides [`SharedService`], a thin newtype around
//! `Arc<S4Service<B>>` with a delegating `impl S3` that forwards every
//! call to the inner service. Cloning a `SharedService` is one
//! `Arc::clone` — the scanner keeps one clone, the s3s service builder
//! consumes another.
//!
//! ## why a newtype with a single-shot impl macro
//!
//! `#[async_trait::async_trait]` is a proc-macro that rewrites every
//! `async fn` it can directly see into a desugared `Pin<Box<dyn Future
//! ...>>` return. Proc macros run **before** `macro_rules!` expand, so a
//! per-method `delegate!` macro inside the impl body would be invisible
//! to `async_trait` (the result is `E0195` lifetime mismatches on every
//! method). To work around that ordering, the entire `impl S3 for
//! SharedService<B>` block is generated by the [`s3_delegate_impl!`]
//! `macro_rules!` below, so `#[async_trait::async_trait]` sees the
//! `async fn`s after the macro has expanded.

use std::sync::Arc;

use s3s::dto::*;
use s3s::{S3, S3Request, S3Response, S3Result};

use crate::service::S4Service;

/// Cheap-clone shared handle to an `S4Service<B>`. Implements `S3` by
/// delegating every call through the inner Arc. Construct via
/// [`SharedService::new`]; `Clone` bumps the refcount only.
pub struct SharedService<B: S3 + Send + Sync + 'static> {
    inner: Arc<S4Service<B>>,
}

impl<B: S3 + Send + Sync + 'static> SharedService<B> {
    /// Wrap an existing `Arc<S4Service<B>>`. Useful when the caller
    /// already holds the `Arc` (e.g. the lifecycle scheduler in
    /// `main.rs` clones it for the background task before handing the
    /// service to the s3s builder).
    #[must_use]
    pub fn new(inner: Arc<S4Service<B>>) -> Self {
        Self { inner }
    }

    /// Borrow the underlying `Arc` so the lifecycle scanner /
    /// background scheduler can issue `S3` calls without re-cloning.
    #[must_use]
    pub fn arc(&self) -> &Arc<S4Service<B>> {
        &self.inner
    }
}

impl<B: S3 + Send + Sync + 'static> Clone for SharedService<B> {
    fn clone(&self) -> Self {
        Self {
            inner: Arc::clone(&self.inner),
        }
    }
}

impl<B: S3 + Send + Sync + 'static> std::fmt::Debug for SharedService<B> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("SharedService")
            .field("inner", &"<Arc<S4Service<...>>>")
            .finish()
    }
}

/// Generate the full delegating `impl S3 for SharedService<B>` block.
/// Macro-emitted so `#[async_trait::async_trait]` can rewrite each
/// `async fn` (proc macros run before `macro_rules!` expand, so a
/// per-method macro inside the impl body would be invisible to
/// `async_trait`).
macro_rules! s3_delegate_impl {
    ( $( ($name:ident, $input:ident, $output:ident) ),* $(,)? ) => {
        #[async_trait::async_trait]
        impl<B: S3 + Send + Sync + 'static> S3 for SharedService<B> {
            $(
                async fn $name(
                    &self,
                    req: S3Request<$input>,
                ) -> S3Result<S3Response<$output>> {
                    (*self.inner).$name(req).await
                }
            )*
        }
    };
}

s3_delegate_impl! {
    (abort_multipart_upload, AbortMultipartUploadInput, AbortMultipartUploadOutput),
    (complete_multipart_upload, CompleteMultipartUploadInput, CompleteMultipartUploadOutput),
    (copy_object, CopyObjectInput, CopyObjectOutput),
    (create_bucket, CreateBucketInput, CreateBucketOutput),
    (create_bucket_metadata_table_configuration, CreateBucketMetadataTableConfigurationInput, CreateBucketMetadataTableConfigurationOutput),
    (create_multipart_upload, CreateMultipartUploadInput, CreateMultipartUploadOutput),
    (create_session, CreateSessionInput, CreateSessionOutput),
    (delete_bucket, DeleteBucketInput, DeleteBucketOutput),
    (delete_bucket_analytics_configuration, DeleteBucketAnalyticsConfigurationInput, DeleteBucketAnalyticsConfigurationOutput),
    (delete_bucket_cors, DeleteBucketCorsInput, DeleteBucketCorsOutput),
    (delete_bucket_encryption, DeleteBucketEncryptionInput, DeleteBucketEncryptionOutput),
    (delete_bucket_intelligent_tiering_configuration, DeleteBucketIntelligentTieringConfigurationInput, DeleteBucketIntelligentTieringConfigurationOutput),
    (delete_bucket_inventory_configuration, DeleteBucketInventoryConfigurationInput, DeleteBucketInventoryConfigurationOutput),
    (delete_bucket_lifecycle, DeleteBucketLifecycleInput, DeleteBucketLifecycleOutput),
    (delete_bucket_metadata_table_configuration, DeleteBucketMetadataTableConfigurationInput, DeleteBucketMetadataTableConfigurationOutput),
    (delete_bucket_metrics_configuration, DeleteBucketMetricsConfigurationInput, DeleteBucketMetricsConfigurationOutput),
    (delete_bucket_ownership_controls, DeleteBucketOwnershipControlsInput, DeleteBucketOwnershipControlsOutput),
    (delete_bucket_policy, DeleteBucketPolicyInput, DeleteBucketPolicyOutput),
    (delete_bucket_replication, DeleteBucketReplicationInput, DeleteBucketReplicationOutput),
    (delete_bucket_tagging, DeleteBucketTaggingInput, DeleteBucketTaggingOutput),
    (delete_bucket_website, DeleteBucketWebsiteInput, DeleteBucketWebsiteOutput),
    (delete_object, DeleteObjectInput, DeleteObjectOutput),
    (delete_object_tagging, DeleteObjectTaggingInput, DeleteObjectTaggingOutput),
    (delete_objects, DeleteObjectsInput, DeleteObjectsOutput),
    (delete_public_access_block, DeletePublicAccessBlockInput, DeletePublicAccessBlockOutput),
    (get_bucket_accelerate_configuration, GetBucketAccelerateConfigurationInput, GetBucketAccelerateConfigurationOutput),
    (get_bucket_acl, GetBucketAclInput, GetBucketAclOutput),
    (get_bucket_analytics_configuration, GetBucketAnalyticsConfigurationInput, GetBucketAnalyticsConfigurationOutput),
    (get_bucket_cors, GetBucketCorsInput, GetBucketCorsOutput),
    (get_bucket_encryption, GetBucketEncryptionInput, GetBucketEncryptionOutput),
    (get_bucket_intelligent_tiering_configuration, GetBucketIntelligentTieringConfigurationInput, GetBucketIntelligentTieringConfigurationOutput),
    (get_bucket_inventory_configuration, GetBucketInventoryConfigurationInput, GetBucketInventoryConfigurationOutput),
    (get_bucket_lifecycle_configuration, GetBucketLifecycleConfigurationInput, GetBucketLifecycleConfigurationOutput),
    (get_bucket_location, GetBucketLocationInput, GetBucketLocationOutput),
    (get_bucket_logging, GetBucketLoggingInput, GetBucketLoggingOutput),
    (get_bucket_metadata_table_configuration, GetBucketMetadataTableConfigurationInput, GetBucketMetadataTableConfigurationOutput),
    (get_bucket_metrics_configuration, GetBucketMetricsConfigurationInput, GetBucketMetricsConfigurationOutput),
    (get_bucket_notification_configuration, GetBucketNotificationConfigurationInput, GetBucketNotificationConfigurationOutput),
    (get_bucket_ownership_controls, GetBucketOwnershipControlsInput, GetBucketOwnershipControlsOutput),
    (get_bucket_policy, GetBucketPolicyInput, GetBucketPolicyOutput),
    (get_bucket_policy_status, GetBucketPolicyStatusInput, GetBucketPolicyStatusOutput),
    (get_bucket_replication, GetBucketReplicationInput, GetBucketReplicationOutput),
    (get_bucket_request_payment, GetBucketRequestPaymentInput, GetBucketRequestPaymentOutput),
    (get_bucket_tagging, GetBucketTaggingInput, GetBucketTaggingOutput),
    (get_bucket_versioning, GetBucketVersioningInput, GetBucketVersioningOutput),
    (get_bucket_website, GetBucketWebsiteInput, GetBucketWebsiteOutput),
    (get_object, GetObjectInput, GetObjectOutput),
    (get_object_acl, GetObjectAclInput, GetObjectAclOutput),
    (get_object_attributes, GetObjectAttributesInput, GetObjectAttributesOutput),
    (get_object_legal_hold, GetObjectLegalHoldInput, GetObjectLegalHoldOutput),
    (get_object_lock_configuration, GetObjectLockConfigurationInput, GetObjectLockConfigurationOutput),
    (get_object_retention, GetObjectRetentionInput, GetObjectRetentionOutput),
    (get_object_tagging, GetObjectTaggingInput, GetObjectTaggingOutput),
    (get_object_torrent, GetObjectTorrentInput, GetObjectTorrentOutput),
    (get_public_access_block, GetPublicAccessBlockInput, GetPublicAccessBlockOutput),
    (head_bucket, HeadBucketInput, HeadBucketOutput),
    (head_object, HeadObjectInput, HeadObjectOutput),
    (list_bucket_analytics_configurations, ListBucketAnalyticsConfigurationsInput, ListBucketAnalyticsConfigurationsOutput),
    (list_bucket_intelligent_tiering_configurations, ListBucketIntelligentTieringConfigurationsInput, ListBucketIntelligentTieringConfigurationsOutput),
    (list_bucket_inventory_configurations, ListBucketInventoryConfigurationsInput, ListBucketInventoryConfigurationsOutput),
    (list_bucket_metrics_configurations, ListBucketMetricsConfigurationsInput, ListBucketMetricsConfigurationsOutput),
    (list_buckets, ListBucketsInput, ListBucketsOutput),
    (list_directory_buckets, ListDirectoryBucketsInput, ListDirectoryBucketsOutput),
    (list_multipart_uploads, ListMultipartUploadsInput, ListMultipartUploadsOutput),
    (list_object_versions, ListObjectVersionsInput, ListObjectVersionsOutput),
    (list_objects, ListObjectsInput, ListObjectsOutput),
    (list_objects_v2, ListObjectsV2Input, ListObjectsV2Output),
    (list_parts, ListPartsInput, ListPartsOutput),
    (post_object, PostObjectInput, PostObjectOutput),
    (put_bucket_accelerate_configuration, PutBucketAccelerateConfigurationInput, PutBucketAccelerateConfigurationOutput),
    (put_bucket_acl, PutBucketAclInput, PutBucketAclOutput),
    (put_bucket_analytics_configuration, PutBucketAnalyticsConfigurationInput, PutBucketAnalyticsConfigurationOutput),
    (put_bucket_cors, PutBucketCorsInput, PutBucketCorsOutput),
    (put_bucket_encryption, PutBucketEncryptionInput, PutBucketEncryptionOutput),
    (put_bucket_intelligent_tiering_configuration, PutBucketIntelligentTieringConfigurationInput, PutBucketIntelligentTieringConfigurationOutput),
    (put_bucket_inventory_configuration, PutBucketInventoryConfigurationInput, PutBucketInventoryConfigurationOutput),
    (put_bucket_lifecycle_configuration, PutBucketLifecycleConfigurationInput, PutBucketLifecycleConfigurationOutput),
    (put_bucket_logging, PutBucketLoggingInput, PutBucketLoggingOutput),
    (put_bucket_metrics_configuration, PutBucketMetricsConfigurationInput, PutBucketMetricsConfigurationOutput),
    (put_bucket_notification_configuration, PutBucketNotificationConfigurationInput, PutBucketNotificationConfigurationOutput),
    (put_bucket_ownership_controls, PutBucketOwnershipControlsInput, PutBucketOwnershipControlsOutput),
    (put_bucket_policy, PutBucketPolicyInput, PutBucketPolicyOutput),
    (put_bucket_replication, PutBucketReplicationInput, PutBucketReplicationOutput),
    (put_bucket_request_payment, PutBucketRequestPaymentInput, PutBucketRequestPaymentOutput),
    (put_bucket_tagging, PutBucketTaggingInput, PutBucketTaggingOutput),
    (put_bucket_versioning, PutBucketVersioningInput, PutBucketVersioningOutput),
    (put_bucket_website, PutBucketWebsiteInput, PutBucketWebsiteOutput),
    (put_object, PutObjectInput, PutObjectOutput),
    (put_object_acl, PutObjectAclInput, PutObjectAclOutput),
    (put_object_legal_hold, PutObjectLegalHoldInput, PutObjectLegalHoldOutput),
    (put_object_lock_configuration, PutObjectLockConfigurationInput, PutObjectLockConfigurationOutput),
    (put_object_retention, PutObjectRetentionInput, PutObjectRetentionOutput),
    (put_object_tagging, PutObjectTaggingInput, PutObjectTaggingOutput),
    (put_public_access_block, PutPublicAccessBlockInput, PutPublicAccessBlockOutput),
    (restore_object, RestoreObjectInput, RestoreObjectOutput),
    (select_object_content, SelectObjectContentInput, SelectObjectContentOutput),
    (upload_part, UploadPartInput, UploadPartOutput),
    (upload_part_copy, UploadPartCopyInput, UploadPartCopyOutput),
    (write_get_object_response, WriteGetObjectResponseInput, WriteGetObjectResponseOutput),
}
