// Copyright 2024 RustFS Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

pub mod account;
pub(crate) mod account_audit;
pub mod account_info;
pub mod audit;
mod audit_runtime_config;
pub mod batch_job;
pub mod bucket_meta;
pub mod cluster_snapshot;
pub mod config_admin;
pub mod diagnostics;
pub mod durability;
pub mod event;
pub mod extensions;
pub mod group;
pub mod heal;
pub mod health;
pub(crate) mod iam_error;
pub mod idp_compat;
pub mod ilm_transition;
pub mod inspect_archive;
pub mod is_admin;
pub mod kms;
pub mod kms_audit;
pub mod kms_backup;
pub mod kms_dynamic;
pub mod kms_key_lifecycle;
pub mod kms_key_metadata;
pub mod kms_keys;
pub mod kms_management;
pub mod kms_rekey;
pub mod metrics;
pub mod mfa;
pub mod module_switch;
mod notify_runtime_access;
pub mod object_data_cache;
pub mod object_zip_download;
pub mod oidc;
pub mod on_demand_migration;
pub mod plugins_catalog;
pub mod plugins_instances;
pub mod policies;
pub mod pools;
pub mod profile;
pub mod profile_admin;
pub mod quota;
pub mod rebalance;
pub mod replication;
pub mod scanner;
pub mod service_account;
pub mod site_replication;
pub mod sts;
pub mod system;
pub mod table_catalog;
mod target_descriptor;
pub mod tier;
pub mod tls_debug;
pub mod trace;
pub mod usage_prefix;
pub mod user;
pub mod user_iam;
pub mod user_lifecycle;
pub mod user_policy_binding;

/// Serialize `payload` as the body of an admin JSON response.
///
/// Routes reached through the `/minio/admin` compat prefix carry an encrypted
/// body; `encode_compatible_admin_payload` decides that from the path, so every
/// handler must go through here rather than serializing directly, or a
/// MinIO client gets plaintext where it expects ciphertext.
pub(crate) fn admin_json_response<T: serde::Serialize>(
    path: &str,
    secret_key: &str,
    status: http::StatusCode,
    payload: &T,
) -> s3s::S3Result<s3s::S3Response<(http::StatusCode, s3s::Body)>> {
    let body = serde_json::to_vec(payload)
        .map_err(|e| s3s::S3Error::with_message(s3s::S3ErrorCode::InternalError, format!("serialize error: {e}")))?;
    let (body, content_type) = crate::admin::utils::encode_compatible_admin_payload(path, secret_key, body)?;

    let mut header = hyper::HeaderMap::new();
    header.insert(s3s::header::CONTENT_TYPE, content_type.parse().expect("valid header value"));
    Ok(s3s::S3Response::with_headers((status, s3s::Body::from(body)), header))
}

pub(crate) async fn supervise_admin_mutation<T>(
    operation: &'static str,
    mutation: impl std::future::Future<Output = s3s::S3Result<T>> + Send + 'static,
) -> s3s::S3Result<T>
where
    T: Send + 'static,
{
    tokio::spawn(mutation).await.map_err(|err| {
        let outcome = if err.is_cancelled() { "cancelled" } else { "panicked" };
        s3s::s3_error!(InternalError, "{} task {}", operation, outcome)
    })?
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_handler_struct_creation() {
        // Test that handler structs can be created
        let _account_handler = account_info::AccountInfoHandler {};
        let _get_config_kv_handler = config_admin::GetConfigKVHandler {};
        let _set_config_kv_handler = config_admin::SetConfigKVHandler {};
        let _del_config_kv_handler = config_admin::DelConfigKVHandler {};
        let _help_config_kv_handler = config_admin::HelpConfigKVHandler {};
        let _get_config_handler = config_admin::GetConfigHandler {};
        let _set_config_handler = config_admin::SetConfigHandler {};
        let _list_audit_targets = audit::ListAuditTargets {};
        let _get_module_switches = module_switch::GetModuleSwitchesHandler {};
        let _get_cluster_snapshot = cluster_snapshot::GetClusterSnapshotHandler {};
        let _get_extension_catalog = extensions::GetExtensionCatalogHandler {};
        let _list_extension_instances = extensions::ListExtensionInstancesHandler {};
        let _get_plugin_catalog = plugins_catalog::GetPluginCatalogHandler {};
        let _create_object_zip_download = object_zip_download::CreateObjectZipDownloadHandler {};
        let _set_on_demand_migration = on_demand_migration::SetBucketOnDemandMigrationHandler {};
        let _get_on_demand_migration = on_demand_migration::GetBucketOnDemandMigrationHandler {};
        let _delete_on_demand_migration = on_demand_migration::DeleteBucketOnDemandMigrationHandler {};
        let _on_demand_migration_status = on_demand_migration::GetBucketOnDemandMigrationStatusHandler {};
        let _list_plugin_instances = plugins_instances::ListPluginInstancesHandler {};
        let _get_plugin_instance = plugins_instances::GetPluginInstanceHandler {};
        let _put_plugin_instance = plugins_instances::PutPluginInstanceHandler {};
        let _delete_plugin_instance = plugins_instances::DeletePluginInstanceHandler {};
        let _update_module_switches = module_switch::UpdateModuleSwitchesHandler {};
        let _service_handler = system::ServiceHandle {};
        let _server_info_handler = system::ServerInfoHandler {};
        let _inspect_data_handler = system::InspectDataHandler {};
        let _storage_info_handler = system::StorageInfoHandler {};
        let _data_usage_handler = system::DataUsageInfoHandler {};
        let _metrics_handler = metrics::MetricsHandler {};
        let _profile_handler = profile_admin::ProfileHandler {};
        let _profile_status_handler = profile_admin::ProfileStatusHandler {};
        let _tls_status_handler = tls_debug::TlsStatusHandler {};
        let _heal_handler = heal::HealHandler {};
        let _bg_heal_handler = heal::BackgroundHealStatusHandler {};
        let _replacement_recovery_status_handler = heal::ReplacementRecoveryStatusHandler {};
        let _replication_metrics_handler = replication::GetReplicationMetricsHandler {};
        let _set_remote_target_handler = replication::SetRemoteTargetHandler {};
        let _list_remote_target_handler = replication::ListRemoteTargetHandler {};
        let _remove_remote_target_handler = replication::RemoveRemoteTargetHandler {};
        let _scanner_status_handler = scanner::ScannerStatusHandler {};
        let _scanner_cycle_state_reset_handler = scanner::ScannerCycleStateResetHandler {};
        let _scanner_usage_state_reset_handler = scanner::ScannerUsageStateResetHandler {};
        let _ilm_expiry_status_handler = scanner::IlmExpiryStatusHandler {};
        let _manual_transition_handler = ilm_transition::ManualTransitionRunHandler {};
        let _manual_transition_status_handler = ilm_transition::ManualTransitionJobStatusHandler {};
        let _manual_transition_cancel_handler = ilm_transition::ManualTransitionJobCancelHandler {};
        let _site_replication_add_handler = site_replication::SiteReplicationAddHandler {};
        let _site_replication_info_handler = site_replication::SiteReplicationInfoHandler {};
        let _site_replication_status_handler = site_replication::SiteReplicationStatusHandler {};
        let _table_catalog_config_handler = table_catalog::GetCatalogConfigHandler {};

        // Just verify they can be created without panicking
        // Test passes if we reach this point without panicking
    }

    #[tokio::test]
    async fn supervised_admin_mutation_survives_waiter_cancellation() {
        let (started_tx, started_rx) = tokio::sync::oneshot::channel();
        let (release_tx, release_rx) = tokio::sync::oneshot::channel();
        let (completed_tx, completed_rx) = tokio::sync::oneshot::channel();

        let waiter = tokio::spawn(async move {
            supervise_admin_mutation("test mutation", async move {
                let _ = started_tx.send(());
                let _ = release_rx.await;
                let _ = completed_tx.send(());
                Ok(())
            })
            .await
        });

        started_rx.await.expect("mutation started");
        waiter.abort();
        release_tx.send(()).expect("release mutation");
        tokio::time::timeout(std::time::Duration::from_secs(1), completed_rx)
            .await
            .expect("detached mutation should complete")
            .expect("completion signal");
    }

    #[tokio::test]
    async fn supervised_admin_mutation_does_not_expose_panic_payload() {
        let error = supervise_admin_mutation::<()>("test mutation", async {
            panic!("do-not-expose-payload");
        })
        .await
        .expect_err("panicking mutation should fail");

        let rendered = error.to_string();
        assert!(rendered.contains("panicked"));
        assert!(!rendered.contains("do-not-expose-payload"));
    }

    // Note: Testing the actual async handler implementations requires:
    // 1. S3Request setup with proper headers, URI, and credentials
    // 2. Global object store initialization
    // 3. IAM system initialization
    // 4. Mock or real backend services
    // 5. Authentication and authorization setup
    //
    // These are better suited for integration tests with proper test infrastructure.
    // The current tests focus on data structures and basic functionality that can be
    // tested in isolation without complex dependencies.
}
