/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License;
 * you may not use this file except in compliance with the Elastic License.
 */
package org.elasticsearch.xpack.watcher.trigger.schedule;

import org.elasticsearch.xpack.core.scheduler.Cron;

import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;

public abstract class CronnableSchedule implements Schedule {

    private static final Comparator<Cron> CRON_COMPARATOR = Comparator.comparing(Cron::expression);

    protected final Cron[] crons;

    CronnableSchedule(String... expressions) {
        this(crons(expressions));
    }

    private CronnableSchedule(Cron... crons) {
        assert crons.length > 0;
        this.crons = crons;
        Arrays.sort(crons, CRON_COMPARATOR);
    }

    @Override
    public long nextScheduledTimeAfter(long startTime, long time) {
        assert time >= startTime;
        long nextTime = Long.MAX_VALUE;
        for (Cron cron : crons) {
            long nextValidTimeAfter = cron.getNextValidTimeAfter(time);

            boolean previousCronExpired = nextTime == -1;
            boolean currentCronValid = nextValidTimeAfter > -1;
            if (previousCronExpired && currentCronValid) {
                nextTime = nextValidTimeAfter;
            } else {
                nextTime = Math.min(nextTime, nextValidTimeAfter);
            }
        }
        return nextTime;
    }

    public Cron[] crons() {
        return crons;
    }

    @Override
    public int hashCode() {
        return Objects.hash((Object[]) crons);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        final CronnableSchedule other = (CronnableSchedule) obj;
        return Objects.deepEquals(this.crons, other.crons);
    }

    static Cron[] crons(String... expressions) {
        Cron[] crons = new Cron[expressions.length];
        for (int i = 0; i < crons.length; i++) {
            crons[i] = new Cron(expressions[i]);
        }
        return crons;
    }
}

@@ -1003,73 +1003,35 @@
     
-long nextTime = Long.MAX_VALUE;%0A        for (Cron cron : 
+return Arrays.stream(
 crons)
- %7B
 %0A   
@@ -1043,33 +1043,20 @@
     
-long nextValidTimeAfter =
+.map(cron -%3E
  cro
@@ -1084,18 +1084,17 @@
 er(time)
-;%0A
+)
 %0A       
@@ -1102,92 +1102,87 @@
     
-boolean previousCronExpired = nextTime == -1;%0A            boolean currentCronValid =
+// filter out expired dates before sorting%0A            .filter(nextValidTime -%3E
  nex
@@ -1195,19 +1195,14 @@
 Time
-After
  %3E -1
-;
+)
 %0A   
@@ -1214,211 +1214,118 @@
     
-if (previousCronExpired && currentCronValid) %7B%0A                nextTime = nextValidTimeAfter;%0A            %7D else %7B%0A                nextTime = Math.min(nextTime, nextValidTimeAfter);%0A            %7D
+.sorted()%0A            .findFirst()%0A            // no date in the future found, return -1 to the caller
 %0A       
  %7D%0A 
@@ -1324,34 +1324,25 @@
     
- %7D%0A
      
-   return nextTime
+.orElse(-1L)
 ;%0A  

Simplify finding next date in cron schedule (#33015)