/*
 * Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file 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.
 */

package software.amazon.awssdk.services.mediastoredata;

import io.reactivex.Flowable;
import java.io.ByteArrayInputStream;
import java.net.URI;
import java.nio.ByteBuffer;
import java.time.Duration;
import java.time.Instant;
import java.util.Optional;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.reactivestreams.Subscriber;
import software.amazon.awssdk.core.async.AsyncRequestBody;
import software.amazon.awssdk.core.internal.async.ByteArrayAsyncRequestBody;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient;
import software.amazon.awssdk.services.mediastore.MediaStoreClient;
import software.amazon.awssdk.services.mediastore.model.Container;
import software.amazon.awssdk.services.mediastore.model.ContainerStatus;
import software.amazon.awssdk.services.mediastore.model.DescribeContainerResponse;
import software.amazon.awssdk.services.mediastoredata.model.PutObjectRequest;
import software.amazon.awssdk.testutils.Waiter;
import software.amazon.awssdk.testutils.service.AwsIntegrationTestBase;

//TODO deleteContainer fails with ContainerInUseException with no error message. Needs investigation
// The test cases work fine.
@Ignore
public class MediaStoreDataIntegrationTest extends AwsIntegrationTestBase {
    private static final String CONTAINER_NAME = "java-sdk-test-" + Instant.now().toEpochMilli();

    private static MediaStoreClient mediaStoreClient;
    private static MediaStoreDataClient syncClientWithApache;
    private static MediaStoreDataClient syncClientWithUrlConnection;
    private static MediaStoreDataAsyncClient asyncClient;

    private static Container container;
    private static PutObjectRequest putObjectRequest;

    @BeforeClass
    public static void setup() {
        mediaStoreClient = MediaStoreClient.builder()
                                           .credentialsProvider(getCredentialsProvider())
                                           .httpClient(ApacheHttpClient.builder().build())
                                           .build();
        container = createContainer();
        URI uri = URI.create(container.endpoint());

        syncClientWithApache = MediaStoreDataClient.builder()
                                                   .endpointOverride(uri)
                                                   .credentialsProvider(getCredentialsProvider())
                                                   .httpClient(ApacheHttpClient.builder().build())
                                                   .build();

        syncClientWithUrlConnection= MediaStoreDataClient.builder()
                                                         .endpointOverride(uri)
                                                         .credentialsProvider(getCredentialsProvider())
                                                         .httpClient(UrlConnectionHttpClient.create())
                                                         .build();

        asyncClient = MediaStoreDataAsyncClient.builder()
                                               .endpointOverride(uri)
                                               .credentialsProvider(getCredentialsProvider())
                                               .build();

        putObjectRequest = PutObjectRequest.builder()
                                           .contentType("application/octet-stream")
                                           .path("/foo")
                                           .build();
    }

    @AfterClass
    public static void tearDown() throws Exception {
        waitContainerToBeActive();
        // Randomly this method is throwing ContainerInUseException
        Thread.sleep(2000);
        mediaStoreClient.deleteContainer(r -> r.containerName(CONTAINER_NAME));
    }

    @org.junit.Test
    public void putObject_sync_apacheHttpClient() {
        syncClientWithApache.putObject(putObjectRequest, RequestBody.fromString("foobar"));
    }

    @org.junit.Test
    public void putObject_sync_urlConnectionHttpClient() {
        syncClientWithUrlConnection.putObject(putObjectRequest,
                                              RequestBody.fromInputStream(
                                                  new ByteArrayInputStream("foobar".getBytes()), 6));
    }

    @org.junit.Test
    public void putObject_asyncClient_withContentLength() {
        asyncClient.putObject(putObjectRequest, AsyncRequestBody.fromString("foobar")).join();
    }

    @org.junit.Test
    public void putObject_asyncClient_withoutContentLength() {
        asyncClient.putObject(putObjectRequest, customAsyncRequestBody()).join();
    }

    private static Container createContainer() {
        mediaStoreClient.createContainer(r -> r.containerName(CONTAINER_NAME));

        DescribeContainerResponse response = waitContainerToBeActive();
        return response.container();
    }

    private static DescribeContainerResponse waitContainerToBeActive() {
        return Waiter.run(() -> mediaStoreClient.describeContainer(r -> r.containerName(CONTAINER_NAME)))
                     .until(r -> ContainerStatus.ACTIVE.equals(r.container().status()))
                     .orFailAfter(Duration.ofMinutes(3));
    }

    private AsyncRequestBody customAsyncRequestBody() {
        return new AsyncRequestBody() {
            @Override
            public Optional<Long> contentLength() {
                return Optional.empty();
            }

            @Override
            public void subscribe(Subscriber<? super ByteBuffer> s) {
                Flowable.fromPublisher(new ByteArrayAsyncRequestBody("Random text".getBytes()))
                        .subscribe(s);
            }
        };
    }
}

@@ -895,33 +895,8 @@
 ss;%0A
-import org.junit.Ignore;%0A
 impo
@@ -1747,146 +1747,8 @@
 e;%0A%0A
-//TODO deleteContainer fails with ContainerInUseException with no error message. Needs investigation%0A// The test cases work fine.%0A@Ignore%0A
 publ
@@ -1916,16 +1916,67 @@
 Milli();
+%0A    private static final String PATH = %22/foo/bar%22;
 %0A%0A    pr
@@ -4027,14 +4027,12 @@
 ath(
-%22/foo%22
+PATH
 )%0A  
@@ -4193,24 +4193,25 @@
 tive();%0A
+%0A
         
 // Rando
@@ -4206,96 +4206,63 @@
     
-// Randomly this method is throwing ContainerInUseException%0A        Thread.sleep(2000
+syncClientWithApache.deleteObject(b -%3E b.path(PATH)
 );%0A
+%0A
     

Fix mediastore data integ test