package demo;

import org.jobrunr.jobs.annotations.Job;
import org.jobrunr.jobs.annotations.Recurring;
import org.jobrunr.jobs.states.StateName;
import org.jobrunr.scheduling.JobScheduler;
import org.jobrunr.storage.StorageProvider;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.util.concurrent.atomic.AtomicInteger;

@SpringBootApplication
public class BootJobs {

    static final AtomicInteger attempts = new AtomicInteger();

    /** An ordinary Spring bean: JobRunr calls its methods later, on a worker. */
    @Component
    public static class Mailer {

        @Job(name = "Welcome mail", retries = 2)
        public void send(String to) {
            int n = attempts.incrementAndGet();
            System.out.println("MAIL attempt " + n + " to " + to + " on " + Thread.currentThread().getName());
            if (n < 2) {
                throw new IllegalStateException("smtp timeout");
            }
        }

        @Recurring(id = "heartbeat", interval = "PT10S")
        @Job(name = "Heartbeat")
        public void heartbeat() {
            System.out.println("HEARTBEAT");
        }
    }

    @Bean
    CommandLineRunner demo(JobScheduler scheduler, Mailer mailer, StorageProvider storage) {
        return args -> {
            System.out.println("STORAGE " + storage.getClass().getSimpleName());
            scheduler.enqueue(() -> mailer.send("asha@example.com"));
            scheduler.schedule(Instant.now().plusSeconds(6), () -> mailer.send("later@example.com"));
        };
    }

    public static void main(String[] args) throws Exception {
        var ctx = SpringApplication.run(BootJobs.class, args);
        Thread.sleep(30_000);                      // wait here, not inside a runner: see the article
        var storage = ctx.getBean(StorageProvider.class);
        for (StateName s : new StateName[] {StateName.SCHEDULED, StateName.ENQUEUED, StateName.PROCESSING, StateName.SUCCEEDED, StateName.FAILED}) {
            System.out.println("STATE " + s + " " + storage.countJobs(s));
        }
        var http = java.net.http.HttpClient.newHttpClient();
        for (String path : new String[] {"/api/servers", "/api/problems"}) {
            var res = http.send(java.net.http.HttpRequest.newBuilder(java.net.URI.create("http://localhost:8000" + path)).build(),
                    java.net.http.HttpResponse.BodyHandlers.ofString());
            System.out.println("GET " + path + " -> " + res.statusCode());
        }
        ctx.close();
    }
}
