/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */
package org.apache.camel.quarkus.component.azure.key.vault.it;

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import com.azure.messaging.eventhubs.EventData;
import com.azure.messaging.eventhubs.EventHubClientBuilder;
import com.azure.messaging.eventhubs.EventHubProducerClient;
import io.restassured.RestAssured;
import org.awaitility.Awaitility;
import org.hamcrest.CoreMatchers;
import org.jboss.logging.Logger;
import org.junit.jupiter.api.Test;

import static org.hamcrest.Matchers.is;

// Azure Key Vault is not supported by Azurite https://github.com/Azure/Azurite/issues/619
abstract class AbstractAzureKeyVaultContextReloadTest {

    private static final Logger LOG = Logger.getLogger(AbstractAzureKeyVaultContextReloadTest.class);
    private static final String AZURE_VAULT_EVENT_HUBS_CONNECTION_STRING = "AZURE_VAULT_EVENT_HUBS_CONNECTION_STRING";

    private String generateRefreshEvent(String secretName) {
        return "[{\n" +
                "  \"subject\": \"" + secretName + "\",\n" +
                "  \"eventType\": \"Microsoft.KeyVault.SecretNewVersionCreated\"\n" +
                "}]";
    }

    @Test
    void contextReload() {
        String secretName = RestAssured.get("/azure-key-vault/configProperty/camel.vault.azure.secrets")
                .then()
                .statusCode(200).extract().body().asString().replace(".*", "");
        String secretValue = "Hello Camel Quarkus Azure Key Vault From Refresh";
        try {
            // Create secret
            RestAssured.given()
                    .body(secretValue)
                    .post("/azure-key-vault/secret/true/{secretName}", secretName)
                    .then()
                    .statusCode(200)
                    .body(is(secretName));
            LOG.infof("Secret created: %s", secretName);

            // Retrieve secret
            RestAssured.given()
                    .get("/azure-key-vault/secret/true/{secretName}", secretName)
                    .then()
                    .statusCode(200);
            LOG.info("Secret verified before refresh.");

            LOG.info("Wait some time for listener to be initialized");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            //force reload by sending a msg
            try (EventHubProducerClient client = new EventHubClientBuilder()
                    .connectionString(System.getenv(AZURE_VAULT_EVENT_HUBS_CONNECTION_STRING))
                    .buildProducerClient()) {

                EventData eventData = new EventData(generateRefreshEvent(secretName).getBytes());
                List<EventData> finalEventData = new LinkedList<>();
                finalEventData.add(eventData);
                LOG.info("Sending refresh event.");
                client.send(finalEventData);
            } catch (Exception e) {
                LOG.info("Failed to send a refresh message", e);
            }

            //await context reload
            Awaitility.await().pollInterval(10, TimeUnit.SECONDS).atMost(5, TimeUnit.MINUTES).untilAsserted(
                    () -> {
                        RestAssured.get("/azure-key-vault/context/reload")
                                .then()
                                .statusCode(200)
                                .body(CoreMatchers.is("true"));
                    });
        } finally {
            // meant to be commented.
            // during development, it may be handy to mark eventhub as completely read. (in case the test is not reading all the messages by itself)
            // Please uncomment the rest of the code to make cursor reset to the latest position after test execution

            //            following code moves the cursor of the hub to the latest position, thus marking all events as read
            //            partition 0 is hardcoded (the resource script creates only one partition)
            //            by default this functionality should not be executed, as the eventbus might be shared for more tests/purposes
            //            even if event stays, it is removed by retention policy in some time (i.e. 1 hpr)
            //            try {
            //                String connectionString = System.getenv(AZURE_VAULT_EVENT_HUBS_CONNECTION_STRING);
            //                String consumerGroup = EventHubClientBuilder.DEFAULT_CONSUMER_GROUP_NAME;
            //
            //                try (EventHubConsumerAsyncClient consumer = new EventHubClientBuilder()
            //                        .connectionString(connectionString)
            //                        .consumerGroup(consumerGroup)
            //                        .buildAsyncConsumerClient()) {
            //
            //                    // Move consumer to the latest position, skipping old messages
            //                    consumer.receiveFromPartition("0", EventPosition.latest())
            //                            .subscribe(event -> {
            //                                System.out.println("Processing new event: " + event.toString());
            //                            }, error -> {
            //                                System.err.println("Error receiving events: " + error);
            //                            });
            //                }
            //            } catch (Exception e) {
            //                LOG.info("Failed to clear event hub.", e);
            //            }

            AzureKeyVaultUtil.deleteSecretImmediately(secretName, true);
        }
    }
}
