import org.h2.jdbcx.JdbcDataSource;
import org.jobrunr.configuration.JobRunr;
import org.jobrunr.jobs.states.StateName;
import org.jobrunr.scheduling.BackgroundJob;
import org.jobrunr.server.BackgroundJobServerConfiguration;
import org.jobrunr.storage.StorageProvider;
import org.jobrunr.storage.sql.common.SqlStorageProviderFactory;

import java.time.Duration;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * What survives a restart. Three modes, run as separate JVMs:
 *   java -cp ".:lib/*" PersistenceDemo executor   a plain executor: tasks are lost when the JVM exits
 *   java -cp ".:lib/*" PersistenceDemo enqueue    JobRunr: enqueue into an H2 file, no worker, exit
 *   java -cp ".:lib/*" PersistenceDemo peek       JobRunr: count what is waiting, without starting a worker
 *   java -cp ".:lib/*" PersistenceDemo work       JobRunr: a new JVM starts a worker and finds the jobs
 */
public class PersistenceDemo {

    public static class Report {
        public void run(int n) {
            System.out.println("  job " + n + " ran in pid " + ProcessHandle.current().pid());
        }
    }

    static StorageProvider storage() {
        var ds = new JdbcDataSource();
        ds.setURL("jdbc:h2:file:./jobrunr-demo-db;AUTO_SERVER=FALSE");
        ds.setUser("sa");
        return SqlStorageProviderFactory.using(ds);
    }

    public static void main(String[] args) throws Exception {
        String mode = args.length > 0 ? args[0] : "enqueue";
        System.out.println("mode=" + mode + " pid=" + ProcessHandle.current().pid());
        switch (mode) {
            case "executor" -> {
                var pool = Executors.newSingleThreadScheduledExecutor();
                for (int i = 1; i <= 3; i++) {
                    int n = i;
                    pool.schedule(() -> System.out.println("  task " + n + " ran"), 5, TimeUnit.SECONDS);
                }
                System.out.println("  scheduled 3 tasks for 5 seconds from now, exiting now");
                pool.shutdownNow();
            }
            case "enqueue" -> {
                var storage = storage();
                JobRunr.configure().useStorageProvider(storage).initialize();   // no background job server here
                var report = new Report();
                for (int i = 1; i <= 3; i++) {
                    int n = i;
                    BackgroundJob.enqueue(() -> report.run(n));
                }
                System.out.println("  ENQUEUED in the database: " + storage.countJobs(StateName.ENQUEUED));
                JobRunr.destroy();
            }
            case "peek" -> {
                var storage = storage();
                // The storage provider only works after initialize(): that is when it receives its JobMapper.
                JobRunr.configure().useStorageProvider(storage).initialize();
                System.out.println("  ENQUEUED waiting in the database: " + storage.countJobs(StateName.ENQUEUED));
                JobRunr.destroy();
            }
            case "work" -> {
                var storage = storage();
                JobRunr.configure().useStorageProvider(storage)
                        .useBackgroundJobServer(BackgroundJobServerConfiguration.usingStandardBackgroundJobServerConfiguration()
                                .andPollInterval(Duration.ofSeconds(5)))
                        .initialize();
                Thread.sleep(12_000);
                System.out.println("  SUCCEEDED: " + storage.countJobs(StateName.SUCCEEDED)
                        + ", ENQUEUED: " + storage.countJobs(StateName.ENQUEUED));
                JobRunr.destroy();
            }
            default -> throw new IllegalArgumentException(mode);
        }
    }
}
