import org.jobrunr.configuration.JobRunr;
import org.jobrunr.jobs.annotations.Job;
import org.jobrunr.jobs.states.StateName;
import org.jobrunr.scheduling.BackgroundJob;
import org.jobrunr.scheduling.cron.Cron;
import org.jobrunr.server.BackgroundJobServerConfiguration;
import org.jobrunr.storage.InMemoryStorageProvider;

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

/**
 * JobRunr 9.0.1 with no Spring and no database: every kind of job, with real output.
 * Compile and run:
 *   javac -parameters -cp "lib/*" JobRunrDemo.java
 *   java -cp ".:lib/*" JobRunrDemo
 */
public class JobRunrDemo {

    static final long START = System.nanoTime();
    static final AtomicInteger flakyAttempts = new AtomicInteger();

    static void log(String s) {
        System.out.printf("[%5.1fs] %s%n", (System.nanoTime() - START) / 1e9, s);
    }

    /** A job is just a public method on an object; JobRunr stores the call, not the lambda. */
    public static class Mailer {
        public void send(String to) {
            log("send mail to " + to + " on " + Thread.currentThread().getName());
        }

        public void heartbeat() {
            log("recurring heartbeat");
        }

        @Job(name = "Flaky export", retries = 2)
        public void flakyExport() {
            int n = flakyAttempts.incrementAndGet();
            log("flaky export attempt " + n);
            if (n < 3) {
                throw new IllegalStateException("upstream timeout on attempt " + n);
            }
            log("flaky export succeeded");
        }
    }

    public static void main(String[] args) throws Exception {
        var storage = new InMemoryStorageProvider();
        JobRunr.configure()
                .useStorageProvider(storage)
                .useBackgroundJobServer(BackgroundJobServerConfiguration.usingStandardBackgroundJobServerConfiguration()
                        .andPollInterval(Duration.ofSeconds(5)))
                .initialize();

        var mailer = new Mailer();
        log("fire-and-forget: enqueue");
        var id = BackgroundJob.enqueue(() -> mailer.send("asha@example.com"));
        log("enqueue returned immediately with id " + id);

        log("scheduled: 8 seconds from now");
        BackgroundJob.schedule(Instant.now().plusSeconds(8), () -> mailer.send("scheduled@example.com"));

        log("recurring: every 15 seconds");
        BackgroundJob.scheduleRecurrently("heartbeat", Duration.ofSeconds(15), () -> mailer.heartbeat());

        log("retrying job: fails twice, @Job(retries = 2)");
        BackgroundJob.enqueue(() -> mailer.flakyExport());

        Thread.sleep(40_000);
        for (StateName s : StateName.values()) {
            log("jobs in state " + s + ": " + storage.countJobs(s));
        }
        JobRunr.destroy();
    }
}
