package org.jenkinsci.plugins.docker.swarm;

import java.io.IOException;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import hudson.model.Node;
import hudson.model.Queue;
import jenkins.model.Jenkins;
import scala.concurrent.duration.Duration;

public class ResetStuckBuildsInQueueActor extends AbstractActor {
    private static final Logger LOGGER = Logger.getLogger(ResetStuckBuildsInQueueActor.class.getName());
    public static final int RESET_MINUTES = 5;
    public static final int CHECK_INTERVAL = 1;

    @Override
    public Receive createReceive() {
        return receiveBuilder().matchAny(o -> resetStuckBuildsInQueue()).build();
    }

    public static Props props() {
        return Props.create(ResetStuckBuildsInQueueActor.class, () -> new ResetStuckBuildsInQueueActor());
    }

    private void resetStuckBuildsInQueue() throws IOException {
        try {
            final Queue.Item[] items = Jenkins.getInstance().getQueue().getItems();
            for (int i = items.length - 1; i >= 0; i--) { // reverse order
                final Queue.Item item = items[i];
                final DockerSwarmLabelAssignmentAction lblAssignmentAction = item
                        .getAction(DockerSwarmLabelAssignmentAction.class); // This can be null here if computer was
                                                                            // never provisioned. Build will sit in
                                                                            // queue forever
                if (lblAssignmentAction != null) {
                    long inQueueForMinutes = TimeUnit.MILLISECONDS
                            .toMinutes(new Date().getTime() - lblAssignmentAction.getProvisionedTime());
                    if (inQueueForMinutes > RESET_MINUTES) {
                        final String computerName = lblAssignmentAction.getLabel().getName();
                        final Node provisionedNode = Jenkins.getInstance().getNode(computerName);
                        if (provisionedNode != null) {
                            LOGGER.info(String.format("Rescheduling %s and Deleting %s computer ", item, computerName));
                            BuildScheduler.scheduleBuild((Queue.BuildableItem) item);
                            ((DockerSwarmAgent) provisionedNode).terminate();
                        }
                    }
                }
            }
        } finally {
            resechedule();
        }

    }

    private void resechedule() {
        ActorSystem system = getContext().getSystem();
        system.scheduler().scheduleOnce(Duration.apply(CHECK_INTERVAL, TimeUnit.MINUTES), getSelf(), "restart",
                getContext().dispatcher(), ActorRef.noSender());
    }
}