package com.cirle.scientific.utils;

import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.Calendar;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;

/**
 * The type Local date time util.
 *
 * @Author: acman
 * @Date: 2018 -09-13
 * @Time: 下午9 :26
 * @Description:
 */
public final class LocalDateTimeUtil {

    private LocalDateTimeUtil() {

    }


    /**
     * Default min datetime
     */
    public static final LocalDateTime MIN_DATE_TIME = LocalDateTime.of(1970, 1, 1, 0, 0, 0);

    /**
     * Default max datetime
     */
    public static final LocalDateTime MAX_DATE_TIME = LocalDateTime.of(2099, 12, 31, 23, 59, 59);

    public static String secondsToTime(Integer seconds){
        if(Objects.isNull(seconds)){
            return "0秒";
        }
        int h=seconds/3600;			//小时
        int m=(seconds%3600)/60;		//分钟
        int s=(seconds%3600)%60;		//秒
        if(h>0){
            return h+"小时"+m+"分钟"+s+"秒";
        }
        if(m>0){
            return m+"分钟"+s+"秒";
        }
        return s+"秒";
    }

    /**
     * 将LocalDateTime转为自定义的时间格式的字符串
     *
     * @param localDateTime the local date time
     * @param format        the format
     * @return date time as string
     */
    public static String getDateTimeAsString(LocalDateTime localDateTime, String format) {
        if (Objects.isNull(localDateTime)) {
            return StringUtils.EMPTY;
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
        return localDateTime.format(formatter);
    }

    public static String getDateAsString(LocalDate localDate , String format){
        if (Objects.isNull(localDate)) {
            return StringUtils.EMPTY;
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
        return localDate.format(formatter);
    }

    /**
     * 将LocalDateTime转化为默认时间格式的字符串
     *
     * @param localDateTime the local date time
     * @return the date time as string
     */
    public static String getDateTimeAsString(LocalDateTime localDateTime) {
        if (Objects.isNull(localDateTime)) {
            return StringUtils.EMPTY;
        }
        return getDateTimeAsString(localDateTime, DatePatternConst.DATE_TIME_PATTERN);
    }


    public static LocalDateTime getByCalendar(Calendar calendar) {
        return LocalDateTime.ofInstant(calendar.toInstant(), ZoneOffset.systemDefault());
    }


    /**
     * Gets local date time or default.
     *
     * @param localDateTime        the local date time
     * @param defaultLocalDateTime the default local date time
     * @return the local date time or default
     */
    public static LocalDateTime getLocalDateTimeOrDefault(LocalDateTime localDateTime, LocalDateTime defaultLocalDateTime) {
        return Optional.ofNullable(localDateTime).orElse(defaultLocalDateTime);
    }

    /**
     * 将Long的timestamp转化成LocalDateTime对象
     *
     * @param timestamp the timestamp
     * @return date time of timestamp
     */
    public static LocalDateTime getDateTimeOfTimestamp(long timestamp) {
        Instant instant = Instant.ofEpochMilli(timestamp);
        ZoneId zone = ZoneId.systemDefault();
        return LocalDateTime.ofInstant(instant, zone);
    }

    /**
     * 将LocalDateTime转为long类型的timestamp
     *
     * @param localDateTime the local date time
     * @return timestamp of date time
     */
    public static long getTimestampOfDateTime(LocalDateTime localDateTime) {
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDateTime.atZone(zone).toInstant();
        return instant.toEpochMilli();
    }

    /**
     * 将某时间字符串转为自定义时间格式的LocalDateTime
     *
     * @param time   the time
     * @param format the format
     * @return local date time
     */
    public static LocalDateTime parseStringToDateTime(String time, String format) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern(format);
        return LocalDateTime.parse(time, df);
    }


    /**
     * 将Timestamp转化成DATE_TIME_PATTERN的格式输出
     *
     * @param timestamp the timestamp
     * @return date time string of timestamp
     */
    public static String getDateTimeStringOfTimestamp(Long timestamp) {
        LocalDateTime localDateTime = LocalDateTimeUtil.getDateTimeOfTimestamp(timestamp);
        return getDateTimeAsString(localDateTime, DatePatternConst.DATE_TIME_PATTERN);
    }

    /**
     * Year month to local date local date.
     *
     * @param yearMonth the year month
     * @return the local date
     */
    public static LocalDate yearMonthToLocalDate(YearMonth yearMonth) {
        return LocalDate.of(yearMonth.getYear(), yearMonth.getMonth(), 1);
    }

    /**
     * Local date to year month year month.
     *
     * @param localDate the local date
     * @return the year month
     */
    public static YearMonth localDateToYearMonth(LocalDate localDate) {
        return YearMonth.of(localDate.getYear(), localDate.getMonthValue());
    }

    /**
     * 将LocalDateTime的时间设置为当天凌晨
     *
     * @param localDateTime the localDateTime
     * @return 当天凌晨
     */
    public static LocalDateTime withTimeAtStartOfDay(LocalDateTime localDateTime) {
        return localDateTime.with(LocalTime.MIN);
    }

    /**
     * 将LocalDateTime的时间设置为当天最后一刻
     *
     * @param localDateTime the localDateTime
     * @return 当天最后一刻
     */
    public static LocalDateTime withTimeAtEndOfDay(LocalDateTime localDateTime) {
        return localDateTime.with(LocalTime.MAX);
    }

    /**
     * Min LocalDateTime of a day
     *
     * @return
     */
    public static LocalDateTime minDateTimeOfDay() {
        return LocalDateTime.now().with(LocalTime.MIN);
    }

    /**
     * Max LocalDateTime of a day
     *
     * @return
     */
    public static LocalDateTime maxDateTimeOfDay() {
        return LocalDateTime.now().with(LocalTime.MAX);
    }

    /**
     * StartTime of month
     *
     * @param month
     * @return
     */
    public static LocalDateTime monthStartTime(LocalDateTime month) {
        return month.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
    }

    /**
     * EndTime of month
     *
     * @param month
     * @return
     */
    public static LocalDateTime monthEndTime(LocalDateTime month) {
        return month.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX);
    }

    /**
     * 查询开始和结束时间中的List
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static List<LocalDate> listBetweenDate(LocalDate startDate, LocalDate endDate) {
        List<LocalDate> list = Lists.newArrayList();

        long distance = ChronoUnit.DAYS.between(startDate, endDate);
        if (distance < 1) {
            return list;
        }
        Stream.iterate(startDate, d -> d.plusDays(1)).limit(distance + 1).forEach(list::add);
        return list;
    }

    /**
     * 查询开始和结束时间的的最后一天的list
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static List<LocalDate> listLastDayBetweenDateTime(LocalDateTime startDate, LocalDateTime endDate) {
        List<LocalDate> list = Lists.newArrayList();

        long distance = ChronoUnit.MONTHS.between(startDate, endDate);
        if (distance < 1) {
            LocalDateTime now = LocalDateTime.now();
            if (endDate.isAfter(now)) {
                list.add(now.toLocalDate());
                return list;
            }
            list.add(endDate.toLocalDate());
            return list;
        }

        // 取出中间月份的最后一天
        Stream.iterate(startDate, d -> d.plusMonths(1)).limit(distance).forEach(e -> {
            LocalDate lastDay = e.toLocalDate().with(TemporalAdjusters.lastDayOfMonth());
            list.add(lastDay);
        });

        // endTime的那一天
        list.add(endDate.toLocalDate());

        return list;
    }

    /**
     * @param dayOfWeek
     * @return 获取本周指定星期
     */
    public static LocalDateTime findThisWeekday(DayOfWeek dayOfWeek) {
        if (Objects.isNull(dayOfWeek)) {
            return null;
        }
        LocalDateTime now = LocalDate.now().atStartOfDay();
        return now.getDayOfWeek().getValue() < dayOfWeek.getValue() ? now.with(TemporalAdjusters.nextOrSame(dayOfWeek))
                : now.with(TemporalAdjusters.previousOrSame(dayOfWeek));
    }

    /**
     * 两个时间间隔，向上取整
     *
     * @param start
     * @param end
     * @return
     */
    public static Integer timeInterval(LocalDateTime start, LocalDateTime end) {
        if (Objects.nonNull(start) && Objects.nonNull(end)) {
            Long seconds = Duration.between(start, end).getSeconds();
            Double day = Math.ceil(seconds / GlobalConst.SECONDS_OF_DAY);
            String strDay = String.valueOf(day);
            return Integer.parseInt(strDay.substring(0, strDay.length() - 2));
        }
        return GlobalConst.DEFAULT_INTEGER_VALUE;
    }

    /**
     * 转换时间
     *
     * @param time
     * @return LocalDateTime
     */
    public static LocalDateTime convertTime(LocalDateTime time) {
        if (Objects.isNull(time)) {
            return null;
        } else {
            if (time.getYear() <= GlobalConst.MIN_TIME.getYear()) {
                return null;
            } else {
                return time;
            }
        }
    }

    public static int getDays(LocalDateTime start, LocalDateTime end) {
        return (int) (end.toLocalDate().toEpochDay() - start.toLocalDate().toEpochDay());
    }

    /**
     * 获取某天是本周的第几天
     *
     * @param time
     * @return
     */
    public static Integer getDayOfWeekByTime(LocalDateTime time) {
        if (Objects.isNull(time)) {
            return null;
        }

        DayOfWeek dayOfWeek = time.getDayOfWeek();
        switch (dayOfWeek) {
            case MONDAY:
                return 1;
            case TUESDAY:
                return 2;
            case WEDNESDAY:
                return 3;
            case THURSDAY:
                return 4;
            case FRIDAY:
                return 5;
            case SATURDAY:
                return 6;
            case SUNDAY:
                return 7;
            default:
                return null;
        }
    }

    public static Period getDatePeriodBetween(LocalDateTime start, LocalDateTime end) {
        Period period = Period.between(start.toLocalDate(), end.toLocalDate());
        return period;
    }

    public static Period getDatePeriodBetween(long start, long end) {
        return getDatePeriodBetween(getDateTimeOfTimestamp(start), getDateTimeOfTimestamp(end));
    }

    /**
     * 将毫秒值转换为分钟
     * 返回值为double
     *
     * @param milleSeconds
     * @return
     */
    public static double milleSecondsToMinutes(long milleSeconds) {
        if (milleSeconds <= 0) {
            return 0;
        }
        return milleSeconds / 60000.0;
    }
}
