package com.viettel.campaign.utils;

import com.cronutils.model.definition.CronDefinition;
import com.cronutils.model.definition.CronDefinitionBuilder;
import com.cronutils.model.time.ExecutionTime;
import com.cronutils.parser.CronParser;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.quartz.CronExpression;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.Optional;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicReference;

import static com.cronutils.model.CronType.QUARTZ;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;

/**
 * @author anhvd_itsol
 */
@Slf4j
public final class DateTimeUtil {
    public static final long DAY_IN_MILLIS = 86400000L;
    public static interface DateTimeProvider { long now(); }
    private static final AtomicReference<DateTimeProvider> PROVIDER = new AtomicReference<DateTimeProvider>();
    public static final DateTimeProvider getProvider() { return PROVIDER.get(); }
    static {
        PROVIDER.set(new DateTimeProvider() { @Override public long now() { return System.currentTimeMillis(); } });
    }

    public static Date currentTime() {
        return new Date(now());
    }

    public static Date currentDate() {
        return date(now());
    }

    public static final Date date(final long millis) {
        final int offset = getTimeZoneOffset(millis);
        long t = millis - ((t = (millis + offset) % DAY_IN_MILLIS) < 0 ? DAY_IN_MILLIS + t : t);
        t = t + (offset - getTimeZoneOffset(t)); return new Date(t);
    }

    public static int getTimeZoneOffset(long millis) {
        return TimeZone.getDefault().getOffset(millis);
    }

    public static long now() {
        return getProvider().now();
    }

    public static long toMillis(long nanos) {
        return MILLISECONDS.convert(nanos, NANOSECONDS);
    }

    public static long currentTimeMillis() {
        return getProvider().now();
    }

    /**
     * Format
     */
    public static String format(String pattern, long millis) {
        return DateTimeFormat.forPattern(pattern).print(millis);
    }

    public static String format(String pattern, Date date, String defaultValue) {
        if(date == null) return defaultValue;
        return format(pattern ,date.getTime());
    }

    /**
     *
     */
    public static boolean isValid(final long millis) {
        return millis > 0L;
    }
    /**
     *
     */
    public static long parse(final String pattern, String date) {
        return DateTimeFormat.forPattern(pattern).parseMillis(date);
    }

    public static Date parseDate(final String pattern, String date) {
        return Strings.isEmpty(date) ? null : date(parse(pattern, date));
    }

    /**
     *
     */

    public static boolean isRun(String cron, Date lastCheck){
        boolean isOk = false;
        String format="dd-MMM-YYYY hh:mm:ss";
//        String cronExpression="* * 12 ? * FRI *";
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        CronExpression expression = null;
        try {
            expression = new CronExpression(cron);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        Date  currentDate = new Date();
        assert expression != null;
        Date lastDate = expression.getNextValidTimeAfter(lastCheck);
        long interval =  lastDate.getTime() - currentDate.getTime();
        if(interval <= 0){
            isOk = true;
        }

        return  isOk;
    }
}
