package dst.ass3.elastic;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;

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

import com.github.dockerjava.api.exception.NotFoundException;
import dst.ass3.messaging.RabbitResource;
import dst.ass3.messaging.RequestType;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import dst.ass3.elastic.impl.ElasticityFactory;
import org.springframework.amqp.core.Queue;

public class ContainerServiceTest {

    private static final Logger LOG = LoggerFactory.getLogger(ContainerServiceTest.class);

    @Rule
    public RabbitResource rabbit = new RabbitResource();

    @Rule
    public Timeout timeout = new Timeout(30, TimeUnit.SECONDS);

    IContainerService containerService;
    IElasticityFactory factory;

    @Before
    public void setUp() throws Exception {
        factory = new ElasticityFactory();

        containerService = factory.createContainerService();

        rabbit.getAdmin().declareQueue(new Queue("dst.document"));
        rabbit.getAdmin().declareQueue(new Queue("dst.quiz"));
        rabbit.getAdmin().declareQueue(new Queue("dst.video"));
    }

    @After
    public void tearDown() throws Exception {
        rabbit.getAdmin().deleteQueue("dst.document");
        rabbit.getAdmin().deleteQueue("dst.quiz");
        rabbit.getAdmin().deleteQueue("dst.video");
    }

    @Test
    public void spawnListStop_lifecycleWorks() throws Exception {
        List<ContainerInfo> containers = containerService.listContainers();
        assertThat("Please stop all containers before running the test", containers.size(), is(0));

        ContainerInfo c1 = containerService.startWorker(RequestType.QUIZ);
        LOG.info("Started container {}", c1);

        ContainerInfo c2 = containerService.startWorker(RequestType.DOCUMENT);
        LOG.info("Started container {}", c2);

        ContainerInfo c3 = containerService.startWorker(RequestType.VIDEO);
        LOG.info("Started container {}", c3);

        LOG.info("Waiting for containers to boot...");
        Thread.sleep(5000);

        containers = containerService.listContainers();

        assertThat(containers.size(), is(3));

        LOG.info("Stopping containers...");
        containerService.stopContainer(c1.getContainerId());
        containerService.stopContainer(c2.getContainerId());
        containerService.stopContainer(c3.getContainerId());

        Thread.sleep(5000);

        containers = containerService.listContainers();
        assertThat(containers.size(), is(0));
    }

    @Test(expected = ContainerNotFoundException.class)
    public void stopNonExistingContainer_throwsException() throws Exception {
        containerService.stopContainer("Non-Existing-Id");
    }

    @Test
    public void listContainers_containsCompleteInfo() throws Exception {
        ContainerInfo c1 = containerService.startWorker(RequestType.QUIZ);
        LOG.info("Started container {}", c1);
        LOG.info("Waiting for container to boot...");
        Thread.sleep(5000);
        List<ContainerInfo> containers = containerService.listContainers();
        ContainerInfo containerInfo = containers.stream()
                .filter(c -> c1.getContainerId().equals(c.getContainerId()))
                .findFirst().get();
        assertThat(containerInfo, notNullValue());
        assertThat(containerInfo.getImage(), equalTo("dst/ass3-worker"));
        assertThat(containerInfo.getWorkerType(), equalTo(RequestType.QUIZ));
        assertThat(containerInfo.isRunning(), is(true));
        LOG.info("Stopping container...");
        containerService.stopContainer(containerInfo.getContainerId());
    }

}