/*
 * Copyright 2019, EnMasse authors.
 * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
 */
package io.enmasse.systemtest.bases;

import io.enmasse.iot.model.v1.IoTConfig;
import io.enmasse.iot.model.v1.IoTConfigBuilder;
import io.enmasse.iot.model.v1.IoTProject;
import io.enmasse.systemtest.CertBundle;
import io.enmasse.systemtest.CustomLogger;
import io.enmasse.systemtest.Endpoint;
import io.enmasse.systemtest.Environment;
import io.enmasse.systemtest.SystemtestsKubernetesApps;
import io.enmasse.systemtest.UserCredentials;
import io.enmasse.systemtest.amqp.AmqpClientFactory;
import io.enmasse.systemtest.utils.CertificateUtils;
import io.enmasse.systemtest.utils.IoTUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.slf4j.Logger;

import java.nio.ByteBuffer;
import java.util.UUID;

public abstract class IoTTestBaseWithShared extends IoTTestBase {

    protected static Logger log = CustomLogger.getLogger();

    private final String addressSpace = "shared-address-space";

    protected IoTConfig sharedConfig;
    protected IoTProject sharedProject;

    private UserCredentials credentials;
    protected AmqpClientFactory iotAmqpClientFactory;

    @BeforeEach
    public void setUpSharedIoTProject() throws Exception {

        this.credentials = new UserCredentials(UUID.randomUUID().toString(), UUID.randomUUID().toString());

        if (sharedConfig == null) {
            Endpoint infinispanEndpoint = SystemtestsKubernetesApps.deployInfinispanServer(kubernetes.getNamespace());
            CertBundle certBundle = CertificateUtils.createCertBundle();
            sharedConfig = new IoTConfigBuilder()
                    .withNewMetadata()
                    .withName("default")
                    .endMetadata()
                    .withNewSpec()
                    .withNewServices()
                    .withNewDeviceRegistry()
                    .withNewInfinispan()
                    .withInfinispanServerAddress(infinispanEndpoint.toString())
                    .endInfinispan()
                    .endDeviceRegistry()
                    .endServices()
                    .withNewAdapters()
                    .withNewMqtt()
                    .withNewEndpoint()
                    .withNewKeyCertificateStrategy()
                    .withCertificate(ByteBuffer.wrap(certBundle.getCert().getBytes()))
                    .withKey(ByteBuffer.wrap(certBundle.getKey().getBytes()))
                    .endKeyCertificateStrategy()
                    .endEndpoint()
                    .endMqtt()
                    .endAdapters()
                    .endSpec()
                    .build();

            createIoTConfig(sharedConfig);
        }

        if (sharedProject == null) {
            sharedProject = IoTUtils.getBasicIoTProjectObject("shared-iot-project", this.addressSpace, this.iotProjectNamespace);
            createIoTProject(sharedProject);
        }

        this.iotAmqpClientFactory = createAmqpClientFactory();
    }

    public String getAddressSpace() {
        return this.addressSpace;
    }

    /**
     * Create a new {@link AmqpClientFactory} for the IoTProject's address space.
     */
    private AmqpClientFactory createAmqpClientFactory() throws Exception {

        getUserApiClient().createUser(this.addressSpace, this.credentials);
        return new AmqpClientFactory(kubernetes, Environment.getInstance(), getAddressSpace(this.addressSpace), this.credentials);

    }

    @AfterEach
    public void tearDownSharedIoTProject(ExtensionContext context) throws Exception {
        if (context.getExecutionException().isPresent()) { //test failed
            if (!environment.skipCleanup()) {
                log.info("Shared IoTProject will be removed");
                var iotProjectApiClient = kubernetes.getIoTProjectClient(sharedProject.getMetadata().getNamespace());
                if (iotProjectApiClient.withName(sharedProject.getMetadata().getName()).get() != null) {
                    IoTUtils.deleteIoTProjectAndWait(kubernetes, sharedProject, addressApiClient);
                } else {
                    log.info("IoTProject '" + sharedProject.getMetadata().getName() + "' doesn't exists!");
                }
                sharedProject = null;
                log.info("Shared IoTConfig will be removed");
                var iotConfigApiClient = kubernetes.getIoTConfigClient();
                if (iotConfigApiClient.withName(sharedConfig.getMetadata().getName()).get() != null) {
                    IoTUtils.deleteIoTConfigAndWait(kubernetes, sharedConfig);
                } else {
                    log.info("IoTConfig '" + sharedConfig.getMetadata().getName() + "' doesn't exists!");
                }
                log.info("Infinispan server will be removed");
                SystemtestsKubernetesApps.deleteInfinispanServer(kubernetes.getNamespace());
                sharedConfig = null;
            } else {
                log.warn("Remove shared iotproject when test failed - SKIPPED!");
            }
        }

        if (this.iotAmqpClientFactory != null) {
            this.iotAmqpClientFactory.close();
            this.iotAmqpClientFactory = null;
        }
    }

    @Override
    public IoTConfig getSharedIoTConfig() {
        return sharedConfig;
    }

    @Override
    public IoTProject getSharedIoTProject() {
        return sharedProject;
    }

}

@@ -1025,16 +1025,22 @@
 otected 
+final 
 static L
@@ -3823,24 +3823,73 @@
 leanup()) %7B%0A
+                if (sharedProject != null) %7B%0A    
             
@@ -3951,24 +3951,28 @@
             
+  
+  
 var iotProje
@@ -4073,24 +4073,28 @@
             
+    
 if (iotProje
@@ -4182,32 +4182,36 @@
                 
+  
+  
 IoTUtils.deleteI
@@ -4281,32 +4281,36 @@
                 
+    
 %7D else %7B%0A       
@@ -4314,32 +4314,36 @@
                 
+  
+  
 log.info(%22IoTPro
@@ -4348,19 +4348,37 @@
 roject '
-%22 +
+%7B%7D' doesn't exists!%22,
  sharedP
@@ -4411,33 +4411,15 @@
 me()
- + %22' doesn't exists!%22);%0A
+);%0A    
     
@@ -4424,32 +4424,36 @@
               %7D%0A
+    
                 
@@ -4466,32 +4466,98 @@
 Project = null;%0A
+                %7D%0A                if (sharedConfig != null) %7B%0A    
                 
@@ -4614,24 +4614,28 @@
             
+    
 var iotConfi
@@ -4676,24 +4676,28 @@
 igClient();%0A
+    
             
@@ -4799,32 +4799,36 @@
                 
+    
 IoTUtils.deleteI
@@ -4862,32 +4862,36 @@
  sharedConfig);%0A
+    
                 
@@ -4911,32 +4911,36 @@
                 
+    
 log.info(%22IoTCon
@@ -4948,11 +4948,29 @@
 ig '
-%22 +
+%7B%7D' doesn't exists!%22,
  sha
@@ -5006,32 +5006,32 @@
 me()
- + %22' doesn't exists!%22);
+);%0A                    %7D
 %0A   

Fix NPEs when the test failed