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


import io.enmasse.systemtest.CustomLogger;
import io.enmasse.systemtest.TestUtils;
import io.enmasse.systemtest.cmdclients.DockerCmdClient;
import io.enmasse.systemtest.timemeasuring.Operation;
import io.enmasse.systemtest.timemeasuring.TimeMeasuringSystem;
import org.slf4j.Logger;

import java.io.File;
import java.net.URL;
import java.util.Arrays;

public class SeleniumContainers {

    private static Logger log = CustomLogger.getLogger();
    private static final String FIREFOX_IMAGE = "selenium/standalone-firefox";
    private static final String CHROME_IMAGE = "selenium/standalone-chrome";
    private static final String FIREFOX_CONTAINER_NAME = "selenium-firefox";
    private static final String CHROME_CONTAINER_NAME = "selenium-chrome";
    private static final String RUNNING_CONTAINER_MESSAGE = "'%s' is not in running state!";
    private static final int RETRY = 10;

    public static void deployFirefoxContainer() throws Exception {
        String operationID = TimeMeasuringSystem.startOperation(Operation.CREATE_SELENIUM_CONTAINER);
        log.info("Deploy firefox container");
        DockerCmdClient.pull("docker.io", FIREFOX_IMAGE, "latest");
        try {
            TestUtils.doCommandNTimes(RETRY, () -> {
                stopAndRemoveFirefoxContainer();
                DockerCmdClient.runContainer(FIREFOX_IMAGE, FIREFOX_CONTAINER_NAME,
                        generateSeleniumOpts("4444", ":99"));
                copyRheaWebPageFirefox();
                return checkSeleniumContainer(FIREFOX_CONTAINER_NAME, "localhost", 4444);
            });
        } catch (Exception e) {
            log.error(String.format(RUNNING_CONTAINER_MESSAGE, FIREFOX_CONTAINER_NAME));
            throw e;
        } finally {
            TimeMeasuringSystem.stopOperation(operationID);
        }
    }

    public static void deployChromeContainer() throws Exception {
        String operationID = TimeMeasuringSystem.startOperation(Operation.CREATE_SELENIUM_CONTAINER);
        log.info("Deploy chrome container");
        DockerCmdClient.pull("docker.io", CHROME_IMAGE, "latest");
        try {
            TestUtils.doCommandNTimes(RETRY, () -> {
                stopAndRemoveChromeContainer();
                DockerCmdClient.runContainer(CHROME_IMAGE, CHROME_CONTAINER_NAME,
                        generateSeleniumOpts("4443", ":98"));
                copyRheaWebPageChrome();
                return checkSeleniumContainer(CHROME_CONTAINER_NAME, "localhost", 4443);
            });
        } catch (Exception e) {
            log.error(String.format(RUNNING_CONTAINER_MESSAGE, CHROME_CONTAINER_NAME));
            throw e;
        } finally {
            TimeMeasuringSystem.stopOperation(operationID);
        }
    }

    public static void stopAndRemoveFirefoxContainer() {
        String operationID = TimeMeasuringSystem.startOperation(Operation.DELETE_SELENIUM_CONTAINER);
        DockerCmdClient.stopContainer(FIREFOX_CONTAINER_NAME);
        DockerCmdClient.removeContainer(FIREFOX_CONTAINER_NAME);
        TimeMeasuringSystem.stopOperation(operationID);
    }

    public static void stopAndRemoveChromeContainer() {
        String operationID = TimeMeasuringSystem.startOperation(Operation.DELETE_SELENIUM_CONTAINER);
        DockerCmdClient.stopContainer(CHROME_CONTAINER_NAME);
        DockerCmdClient.removeContainer(CHROME_CONTAINER_NAME);
        TimeMeasuringSystem.stopOperation(operationID);
    }

    private static void copyRheaWebPage(String containerName) {
        File rheaHtml = new File("src/main/resources/rhea.html");
        File rheaJs = new File("client_executable/rhea/dist/rhea.js");

        DockerCmdClient.copyToContainer(containerName, rheaHtml.getAbsolutePath(), "/opt/rhea.html");
        DockerCmdClient.copyToContainer(containerName, rheaJs.getAbsolutePath(), "/opt/rhea.js");
    }

    public static void restartFirefoxContainer() throws Exception {
        log.info("Restarting container {}", FIREFOX_CONTAINER_NAME);
        try {
            TestUtils.doCommandNTimes(RETRY, () -> {
                DockerCmdClient.restartContainer(FIREFOX_CONTAINER_NAME);
                return checkSeleniumContainer(FIREFOX_CONTAINER_NAME, "localhost", 4444);
            });
        } catch (Exception e) {
            log.error(String.format(RUNNING_CONTAINER_MESSAGE, FIREFOX_CONTAINER_NAME));
            throw e;
        }
    }

    public static void restartChromeContainer() throws Exception {
        log.info("Restarting container {}", CHROME_CONTAINER_NAME);
        try {
            TestUtils.doCommandNTimes(RETRY, () -> {
                DockerCmdClient.restartContainer(CHROME_CONTAINER_NAME);
                return checkSeleniumContainer(CHROME_CONTAINER_NAME, "localhost", 4443);
            });
        } catch (Exception e) {
            log.error(String.format(RUNNING_CONTAINER_MESSAGE, CHROME_CONTAINER_NAME));
            throw e;
        }
    }

    public static void copyRheaWebPageChrome() {
        copyRheaWebPage(CHROME_CONTAINER_NAME);
    }

    public static void copyRheaWebPageFirefox() {
        copyRheaWebPage(FIREFOX_CONTAINER_NAME);
    }

    private static String[] generateSeleniumOpts(String port, String display) {
        return Arrays.asList(
                "-d",
                "-p", String.format("%s:%s", port, port),
                "--network", "host",
                "-e", String.format("DISPLAY=%s", display),
                "-e", String.format("SE_OPTS=-port %s", port)).toArray(new String[0]);
    }

    private static boolean checkSeleniumContainer(String containerName, String host, int port) throws Exception {
        return TestUtils.doCommandNTimes(10, () -> DockerCmdClient.isContainerRunning(containerName) &&
                TestUtils.pingHost(host, port, 10000) &&
                TestUtils.isReachable(new URL(String.format("http://%s:%s/wd/hub", host, port))));
    }
}
