// 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.

//! End-to-end test for Content-Encoding header handling
//!
//! Tests that the Content-Encoding header is correctly stored during PUT
//! and returned in GET/HEAD responses. This is important for clients that
//! upload pre-compressed content and rely on the header for decompression.

#[cfg(test)]
mod tests {
    use crate::common::{RustFSTestEnvironment, init_logging};
    use aws_sdk_s3::primitives::ByteStream;
    use tracing::info;

    /// Verify Content-Encoding header roundtrips through PUT, GET, and HEAD operations
    #[tokio::test]
    async fn test_content_encoding_roundtrip() {
        init_logging();
        info!("Starting Content-Encoding roundtrip test");

        let mut env = RustFSTestEnvironment::new().await.expect("Failed to create test environment");
        env.start_rustfs_server(vec![]).await.expect("Failed to start RustFS");

        let client = env.create_s3_client();
        let bucket = "content-encoding-test";
        let key = "logs/app.log.zst";
        let content = b"2024-01-15 10:23:45 INFO Application started\n2024-01-15 10:23:46 DEBUG Loading config\n";

        client
            .create_bucket()
            .bucket(bucket)
            .send()
            .await
            .expect("Failed to create bucket");

        info!("Uploading object with Content-Encoding: zstd");
        client
            .put_object()
            .bucket(bucket)
            .key(key)
            .content_type("text/plain")
            .content_encoding("zstd")
            .body(ByteStream::from_static(content))
            .send()
            .await
            .expect("PUT failed");

        info!("Verifying GET response includes Content-Encoding");
        let get_resp = client.get_object().bucket(bucket).key(key).send().await.expect("GET failed");

        assert_eq!(get_resp.content_encoding(), Some("zstd"), "GET should return Content-Encoding: zstd");
        assert_eq!(get_resp.content_type(), Some("text/plain"), "GET should return correct Content-Type");

        let body = get_resp.body.collect().await.unwrap().into_bytes();
        assert_eq!(body.as_ref(), content, "Body content mismatch");

        info!("Verifying HEAD response includes Content-Encoding");
        let head_resp = client
            .head_object()
            .bucket(bucket)
            .key(key)
            .send()
            .await
            .expect("HEAD failed");

        assert_eq!(head_resp.content_encoding(), Some("zstd"), "HEAD should return Content-Encoding: zstd");
        assert_eq!(head_resp.content_type(), Some("text/plain"), "HEAD should return correct Content-Type");

        client
            .delete_object()
            .bucket(bucket)
            .key(key)
            .send()
            .await
            .expect("DELETE object failed");
        client
            .delete_bucket()
            .bucket(bucket)
            .send()
            .await
            .expect("DELETE bucket failed");
        client
            .list_buckets()
            .send()
            .await
            .expect("RustFS must remain available after deleting a bucket");

        env.stop_server();
    }

    /// Issue #1857: Content-Encoding "aws-chunked" is used by SigV4 streaming clients and must
    /// not be stored or returned. Upload with aws-chunked and verify GET/HEAD do not return it.
    #[tokio::test]
    async fn test_content_encoding_aws_chunked_not_returned_issue_1857() {
        init_logging();
        info!("Issue #1857: aws-chunked must not be persisted or returned");

        let mut env = RustFSTestEnvironment::new().await.expect("Failed to create test environment");
        env.start_rustfs_server(vec![]).await.expect("Failed to start RustFS");

        let client = env.create_s3_client();
        let bucket = "content-encoding-aws-chunked-test";
        let key = "streamed/object.bin";
        let content = b"streaming upload body";

        client
            .create_bucket()
            .bucket(bucket)
            .send()
            .await
            .expect("Failed to create bucket");

        client
            .put_object()
            .bucket(bucket)
            .key(key)
            .content_encoding("aws-chunked")
            .body(ByteStream::from_static(content))
            .send()
            .await
            .expect("PUT failed");

        let get_resp = client.get_object().bucket(bucket).key(key).send().await.expect("GET failed");
        assert_eq!(
            get_resp.content_encoding(),
            None,
            "GET must not return Content-Encoding when only aws-chunked was sent (Issue #1857)"
        );

        let head_resp = client
            .head_object()
            .bucket(bucket)
            .key(key)
            .send()
            .await
            .expect("HEAD failed");
        assert_eq!(
            head_resp.content_encoding(),
            None,
            "HEAD must not return Content-Encoding when only aws-chunked was sent (Issue #1857)"
        );

        env.stop_server();
    }

    /// Issue #2475 / Route A: when aws-chunked is combined with an effective object encoding,
    /// only the effective encoding should roundtrip through GET/HEAD.
    #[tokio::test]
    async fn test_content_encoding_aws_chunked_with_effective_encoding_roundtrip() {
        init_logging();
        info!("aws-chunked,gzip should persist only gzip");

        let mut env = RustFSTestEnvironment::new().await.expect("Failed to create test environment");
        env.start_rustfs_server(vec![]).await.expect("Failed to start RustFS");

        let client = env.create_s3_client();
        let bucket = "content-encoding-aws-chunked-gzip-test";
        let key = "streamed/object.txt";
        let content = b"streaming upload body with effective gzip encoding";

        client
            .create_bucket()
            .bucket(bucket)
            .send()
            .await
            .expect("Failed to create bucket");

        client
            .put_object()
            .bucket(bucket)
            .key(key)
            .content_type("text/plain")
            .content_encoding("aws-chunked,gzip")
            .body(ByteStream::from_static(content))
            .send()
            .await
            .expect("PUT failed");

        let get_resp = client.get_object().bucket(bucket).key(key).send().await.expect("GET failed");
        assert_eq!(
            get_resp.content_encoding(),
            Some("gzip"),
            "GET must return only the effective content encoding after aws-chunked is stripped"
        );
        let body = get_resp.body.collect().await.unwrap().into_bytes();
        assert_eq!(body.as_ref(), content, "Body content mismatch");

        let head_resp = client
            .head_object()
            .bucket(bucket)
            .key(key)
            .send()
            .await
            .expect("HEAD failed");
        assert_eq!(
            head_resp.content_encoding(),
            Some("gzip"),
            "HEAD must return only the effective content encoding after aws-chunked is stripped"
        );

        env.stop_server();
    }
}
