import org.assertj.core.util.Lists;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.*;
import java.util.Date;
import java.util.List;

public class LocalDateTimeUtils {
    public static final String YEAR_MONTH_DAY = "yyyy-MM-dd";
    public static final String DATE_TIME = "yyyy-MM-dd HH:mm:ss";

    public static final String DATE_MINUTE_TIME = "yyyy-MM-dd HH:mm";
    public static final String DATE_TIME_MILLIS = "yyyy-MM-dd HH:mm:ss.SSS";
    public static final String DATE_HOUR_TIME = "yyyy-MM-dd HH";

    //获取当前时间前,几个时间单位的整小时时间戳(参数为毫秒值)如:参数为1,结果是当前时间前一毫秒的当前整小时时间戳
    public static long getNowMillisPre(Long millis) {
        Long milliByTime = getMilliByTime(LocalDateTime.now()) - millis;
        LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(milliByTime / 1000, 0, ZoneOffset.ofHours(8));
        String dateTimeStr = formatTime(localDateTime, DATE_HOUR_TIME);
        DateTimeFormatter df = DateTimeFormatter.ofPattern(DATE_HOUR_TIME);
        Long dateTime = LocalDateTime.parse(dateTimeStr, df).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
        return dateTime;
    }

    //获取当前时间的毫秒值
    public static long getNowMillis() {
        return getMilliByTime(LocalDateTime.now());
    }

    //获取当日凌晨
    public static LocalDateTime getWeeHour() {
        return LocalDateTime.of(LocalDate.now(), LocalTime.of(0, 0, 0));
    }
    //获取本周周一凌晨
    public static long getMondayMill() {
        Date date = new Date();
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();
        LocalDateTime monday = localDateTime.with(TemporalAdjusters.previous(DayOfWeek.SUNDAY)).plusDays(1).withHour(0).withMinute(0).withSecond(0);
        return getMilliByTime(monday);
    }


    //获取当日凌晨 秒
    public static long getWeeHourSecend() {
        return getSecondsByTime(getWeeHour());
    }

    public static long getWeeHourSecend(int day) {
        return getSecondsByTime(getWeeHour().minusDays(day));
    }

    public static long getWeeHourMillis(int day) {
        return getMilliByTime(getWeeHour().minusDays(day));
    }

    //获取当日凌晨 毫秒
    public static long getWeeHourMillis() {
        return getMilliByTime(getWeeHour());
    }

    //获取几天前的凌晨
    public static LocalDateTime getWeeHourAgo(int day) {
        return getWeeHour().minusDays(day);
    }

    //获取几天前的结束时间
    public static LocalDateTime getEndAgo(int day) {
        return getDayEnd(LocalDateTime.now()).minusDays(day);
    }

    //获取以当前时间为止,几小时前的整点 秒值
    public static long getOClockAgo(int number) {
        LocalDateTime hoursAgo = minu(LocalDateTime.now(), number, ChronoUnit.HOURS);
        LocalDateTime oClockAgo = hoursAgo.withMinute(0).withSecond(0).withNano(0);
        return getSecondsByTime(oClockAgo);
    }

    //获取以当前时间为止,几小时前的整点 毫秒值
    public static long getOClockAgoMillis(int number) {
        LocalDateTime hoursAgo = minu(LocalDateTime.now(), number, ChronoUnit.HOURS);
        LocalDateTime oClockAgo = hoursAgo.withMinute(0).withSecond(0).withNano(0);
        return getMilliByTime(oClockAgo);
    }

    public static long getOClockAgoMillis(int number, LocalDateTime now) {
        LocalDateTime hoursAgo = minu(now, number, ChronoUnit.HOURS);
        LocalDateTime oClockAgo = hoursAgo.withMinute(0).withSecond(0).withNano(0);
        return getMilliByTime(oClockAgo);
    }

    //获取以当前时间为止,几分钟前的整分钟 毫秒值
    public static long getMinuteStartAgoMillis(int number) {
        return getMilliByTime(getMinuteStartAgoTime(number));
    }

    public static LocalDateTime getMinuteStartAgoTime(int number) {
        LocalDateTime minutesAgo = minu(LocalDateTime.now(), number, ChronoUnit.MINUTES);
        return minutesAgo.withSecond(0).withNano(0);
    }

    //获取时间集合。整点小时
    @Deprecated
    public static List<String> getTimeList(int beginNum) {
        List<String> list = Lists.newArrayList();
        LocalDateTime now = LocalDateTime.now();
        for (int i = beginNum; i >= 0; i--) {
            String hour = formatTime(now.minusHours(i), "HH");
            list.add(hour + ":00");
        }
        return list;
    }

    public static List<String> getTimeList(int number, ChronoUnit field, String format) {
        List<String> list = Lists.newArrayList();
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime numberAgo = minu(now, number, field);
        int total = number;
        for (int i = 0; i < total; i++) {
            list.add(formatTime(plus(numberAgo, i, field), format));
        }

        return list;
    }

    public static List<String> getTimeList(int number, ChronoUnit field, String format, boolean containNow) {
        List<String> list = Lists.newArrayList();
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime numberAgo = minu(now, number, field);
        int total = number;
        if (containNow) {
            total = number + 1;
        }
        for (int i = 0; i < total; i++) {
            list.add(formatTime(plus(numberAgo, i, field), format));
        }

        return list;
    }

    public static List<String> getTimeList(LocalDateTime beginTime, ChronoUnit field, String format) {
        List<String> list = Lists.newArrayList();
        LocalDateTime now = LocalDateTime.now();
        long diffTwoTime = betweenTwoTime(beginTime, now, field);
        long total = diffTwoTime;
        for (long i = 0; i < total; i++) {
            list.add(formatTime(plus(beginTime, i, field), format));
        }

        return list;
    }

    public static List<String> getTimeList(LocalDateTime beginTime, ChronoUnit field, String format, boolean containNow) {
        List<String> list = Lists.newArrayList();
        LocalDateTime now = LocalDateTime.now();
        long diffTwoTime = betweenTwoTime(beginTime, now, field);
        long total = diffTwoTime;
        if (containNow) {
            total = diffTwoTime + 1;
        }
        for (long i = 0; i < total; i++) {
            list.add(formatTime(plus(beginTime, i, field), format));
        }

        return list;
    }

    public static List<String> getTimeList(ChronoField field, int interval, ChronoUnit fieldUnit, int number, String format) {
        List<String> list = Lists.newArrayList();
        LocalDateTime now = LocalDateTime.now();
        int timeNow = now.get(field);
        int timeToWant = timeNow / interval * interval;
        LocalDateTime timeBegin = now.with(field, timeToWant).minus(number, fieldUnit);
        int total = number / interval;
        for (int i = 0; i < total; i++) {
            list.add(formatTime(plus(timeBegin, i * interval, fieldUnit), format));
        }

        return list;
    }

    public static List<String> getTimeList(ChronoField field, int interval, ChronoUnit fieldUnit, int number, String format, boolean containNow) {
        List<String> list = Lists.newArrayList();
        LocalDateTime now = LocalDateTime.now();
        int timeNow = now.get(field);
        int timeToWant = timeNow / interval * interval;
        LocalDateTime timeBegin = now.with(field, timeToWant).minus(number, fieldUnit);
        int total = number / interval;
        if (containNow) {
            for (int i = 1; i <= total; i++) {
                list.add(formatTime(plus(timeBegin, i * interval, fieldUnit), format));
            }
        } else {
            for (int i = 0; i < total; i++) {
                list.add(formatTime(plus(timeBegin, i * interval, fieldUnit), format));
            }
        }

        return list;
    }

    @Deprecated
    public static List<String> getMinuteList(int countOfHour, int interval, String format) {
        List<String> list = Lists.newArrayList();
        LocalDateTime now = LocalDateTime.now();
        int minuteNow = now.getMinute();
        int minuteToWant = minuteNow / interval * interval;
        LocalDateTime timeBegin = now.withMinute(minuteToWant).minusHours(countOfHour);
        int total = countOfHour * 60 / interval;
        for (int i = 1; i <= total; i++) {
            String time = formatTime(timeBegin.plusMinutes(i * interval), format);
            list.add(time);
        }
        return list;
    }

    public static List<String> getMinuteList(int count, int interval, String format, ChronoUnit field) {
        List<String> list = Lists.newArrayList();
        LocalDateTime now = LocalDateTime.now();
        int minuteNow = now.getMinute();
        int minuteToWant = minuteNow / interval * interval;
        LocalDateTime timeBegin = minu(now.withMinute(minuteToWant), count, ChronoUnit.MINUTES);
        int total = count / interval;
        for (int i = 1; i <= total; i++) {
            String time = formatTime(timeBegin.plusMinutes(i * interval), format);
            list.add(time);
        }
        return list;
    }

    //获取一天的开始时间,2017,7,22 00:00
    public static LocalDateTime getDayStart(LocalDateTime time) {
        return time.withHour(0).withMinute(0).withSecond(0).withNano(0);
    }

    //获取一天的结束时间,2017,7,22 23:59:59.999999999
    public static LocalDateTime getDayEnd(LocalDateTime time) {
        return time.withHour(23).withMinute(59).withSecond(59).withNano(999999999);
    }

    //获取当月第一天。 参数可以是LocalDate、LocalDateTime、LocalTime等。
    //传不同的参数会得到不同的结果。
    public static Temporal getFirstDayOfMonth(Temporal date) {
        return date.with(TemporalAdjusters.firstDayOfMonth());
    }

    public static Temporal getCopyDateToWant(Temporal date, TemporalAdjuster adjuster) {
        return date.with(adjuster);
    }

    //获取当月第一天的凌晨
    public static Long getFirstDayOfCurrentMonth() {
        LocalDate firstDay = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());
        LocalTime weeHour = LocalTime.of(0, 0, 0);
        LocalDateTime firstDayOfCurrentMonth = LocalDateTime.of(firstDay, weeHour);
        return getMilliByTime(firstDayOfCurrentMonth);
    }

    //获取当年第一天的凌晨
    public static LocalDateTime getDayStartThisYear() {
        LocalDateTime firstDay = (LocalDateTime) getCopyDateToWant(LocalDateTime.now(), TemporalAdjusters.firstDayOfYear());
        LocalDateTime dayStart = getDayStart(firstDay);
        return dayStart;
    }

    //获取两个日期的差  field参数为ChronoUnit.*
    public static long betweenTwoTime(LocalDateTime startTime, LocalDateTime endTime, ChronoUnit field) {
        Period period = Period.between(LocalDate.from(startTime), LocalDate.from(endTime));
        if (field == ChronoUnit.YEARS) return period.getYears();
        if (field == ChronoUnit.MONTHS) return period.getYears() * 12 + period.getMonths();
        return field.between(startTime, endTime);
    }

    //日期加上一个数,根据field不同加不同值,field为ChronoUnit.*
    public static LocalDateTime plus(LocalDateTime time, long number, TemporalUnit field) {
        return time.plus(number, field);
    }

    //日期减去一个数,根据field不同减不同值,field参数为ChronoUnit.*
    public static LocalDateTime minu(LocalDateTime time, long number, TemporalUnit field) {
        return time.minus(number, field);
    }

    //获取指定时间的指定格式
    public static String formatTime(LocalDateTime time, String pattern) {
        return time.format(DateTimeFormatter.ofPattern(pattern));
    }

    public static String formatDate(LocalDateTime time) {
        return time.format(DateTimeFormatter.ofPattern(YEAR_MONTH_DAY));
    }

    public static String formatDateTime(LocalDateTime time) {
        return time.format(DateTimeFormatter.ofPattern(DATE_TIME));
    }

    //获取当前时间的指定格式
    public static String formatNow(String pattern) {
        return formatTime(LocalDateTime.now(), pattern);
    }

    //解析指定格式的时间
    public static LocalDateTime parseTime(String time, String pattern) {
        return LocalDateTime.parse(time, DateTimeFormatter.ofPattern(pattern));
    }

    //获取指定日期的毫秒
    public static Long getMilliByTime(LocalDateTime time) {
        return time.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    //获取指定日期的秒
    public static Long getSecondsByTime(LocalDateTime time) {
        return time.atZone(ZoneId.systemDefault()).toInstant().getEpochSecond();
    }

    //Date转换为LocalDateTime
    public static LocalDateTime convertDateToLDT(Date date) {
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    }

    //LocalDateTime转换为Date
    public static Date convertLDTToDate(LocalDateTime time) {
        return Date.from(time.atZone(ZoneId.systemDefault()).toInstant());
    }

    //判断给定时间是否不在当前这个小时内
    public static boolean judgePassedTimeLine(int hourAgo) {
        LocalDateTime now = LocalDateTime.now();
        if (now.getHour() != hourAgo) {
            return true;
        }
        return false;
    }

}