package io.syndesis.qe.bdd;

import io.syndesis.qe.Component;
import io.syndesis.qe.templates.FtpTemplate;
import org.assertj.core.api.Assertions;

import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.openshift.api.model.Build;
import io.syndesis.qe.endpoints.TestSupport;
import io.syndesis.qe.templates.AmqTemplate;
import io.syndesis.qe.templates.SyndesisTemplate;
import io.syndesis.qe.utils.DbUtils;
import io.syndesis.qe.utils.LogCheckerUtils;
import io.syndesis.qe.utils.OpenShiftUtils;
import io.syndesis.qe.utils.SampleDbConnectionManager;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class CommonSteps {

    @Given("^clean default namespace")
    public void cleanNamespace() {
        OpenShiftUtils.getInstance().clean();
    }

    @Given("^clean all builds")
    public void cleanBuilds() {
        OpenShiftUtils.getInstance().getBuildConfigs().forEach(OpenShiftUtils.getInstance()::deleteBuildConfig);
        OpenShiftUtils.getInstance().getBuilds().forEach(OpenShiftUtils.getInstance()::deleteBuild);
    }

    @When("^deploy Syndesis from template")
    public void deploySyndesis() {
        SyndesisTemplate.deploy();
    }

    @Then("^wait for Syndesis to become ready")
    public void waitForSyndeisis() {
       OpenShiftUtils.xtf().waiters()
               .areExactlyNPodsRunning(1, "component", Component.SERVER.getName())
               .timeout(TimeUnit.MINUTES, 10)
               .assertEventually("Deployment failed within given timeout");
    }

    @Then("^verify s2i build of integration \"([^\"]*)\" was finished in duration (\\d+) min$")
    public void verifyBuild(String integrationName, int duration) {
        String sanitizedName = integrationName.toLowerCase().replaceAll(" ", "-");

        Optional<Build> s2iBuild = OpenShiftUtils.getInstance().getBuilds().stream().filter(b -> b.getMetadata().getName().contains(sanitizedName)).findFirst();

        if (s2iBuild.isPresent()) {
            Build build = s2iBuild.get();
            String buildPodName = build.getMetadata().getAnnotations().get("openshift.io/build.pod-name");
            Optional<Pod> buildPod = OpenShiftUtils.getInstance().getPods().stream().filter(p -> p.getMetadata().getName().equals(buildPodName)).findFirst();
            if (buildPod.isPresent()) {
                try {
                    boolean[] patternsInLogs = LogCheckerUtils.findPatternsInLogs(buildPod.get(), Pattern.compile(".*Downloading: \\b.*"));
                    Assertions.assertThat(patternsInLogs).containsOnly(false);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            Assertions.assertThat(build.getStatus().getPhase()).isEqualTo("Complete");
            // % 1_000L is there to parse OpenShift ms format
            Assertions.assertThat(build.getStatus().getDuration() % 1_000L).isLessThan(duration * 60 * 1000);
        } else {
            Assertions.fail("No build found for integration with name " + sanitizedName);
        }
    }

    @Given("^deploy AMQ broker$")
    public void deployAMQBroker() throws Throwable {
        AmqTemplate.deploy();
    }

    @Given("^execute SQL command \"([^\"]*)\"$")
    public void executeSql(String sqlCmd) {
        DbUtils dbUtils = new DbUtils(SampleDbConnectionManager.getInstance().getConnection());
        dbUtils.readSqlOnSampleDb(sqlCmd);
        SampleDbConnectionManager.getInstance().closeConnection();
    }

    @Given("^clean TODO table$")
    public void cleanTodoTable() {
        DbUtils dbUtils = new DbUtils(SampleDbConnectionManager.getInstance().getConnection());
        dbUtils.deleteRecordsInTable("TODO");
        SampleDbConnectionManager.getInstance().closeConnection();
    }

    @Given("^clean application state")
    public void resetState() {
        int responseCode = TestSupport.getInstance().resetDbWithResponse();
        Assertions.assertThat(responseCode).isEqualTo(204);
    }

    @Given("^deploy FTP server$")
    public void deployFTPServier() {
        FtpTemplate.deploy();
    }

    @Given("^clean FTP server$")
    public void cleanFTPServier() {
        FtpTemplate.cleanUp();
    }
}

@@ -185,21 +185,204 @@
 ava.
-util.Optional
+sql.Time;%0Aimport java.util.ArrayList;%0Aimport java.util.EnumSet;%0Aimport java.util.List;%0Aimport java.util.Optional;%0Aimport java.util.concurrent.ExecutorService;%0Aimport java.util.concurrent.Executors
 ;%0Aim
@@ -1149,16 +1149,25 @@
 ().clean
+AndAssert
 ();%0A    
@@ -1656,24 +1656,254 @@
 ndeisis() %7B%0A
+        EnumSet%3CComponent%3E components = EnumSet.allOf(Component.class);%0A%0A        ExecutorService executorService = Executors.newFixedThreadPool(10);%0A        components.forEach(c -%3E %7B%0A            Runnable runnable = () -%3E%0A         
        OpenS
@@ -1943,16 +1943,25 @@
         
+    
+     
 .areExac
@@ -1996,36 +1996,86 @@
 t%22, 
-Component.SERVER.getName())%0A
+c.getName())%0A                        .interval(TimeUnit.SECONDS, 20)%0A         
     
@@ -2113,17 +2113,17 @@
 NUTES, 1
-0
+2
 )%0A      
@@ -2131,16 +2131,25 @@
         
+     
+    
 .assertE
@@ -2162,50 +2162,447 @@
 lly(
-%22Deployment failed within given timeout%22);
+);%0A%0A            executorService.submit(runnable);%0A        %7D);%0A%0A        executorService.shutdown();%0A        try %7B%0A            if (!executorService.awaitTermination(10, TimeUnit.MINUTES)) %7B%0A                executorService.shutdownNow();%0A                Assertions.fail(%22Syndesis didn't initilized in time%22);%0A            %7D%0A        %7D catch (InterruptedException e) %7B%0A            Assertions.fail(%22Syndesis didn't initilized in time%22);%0A        %7D
 %0A   

Add wait for all infra components