package com.base.core.utiles;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;

import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 时间工具类
 *
 * @author ruoyi
 */
@Slf4j
public class DateUtilsCore extends org.apache.commons.lang3.time.DateUtils {

    public static String YYYY = "yyyy";

    public static String YYYY_MM = "yyyy-MM";

    public static String YYYY_MM_DD = "yyyy-MM-dd";

    public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    public static String PATTERN_MILLIS = "yyyy-MM-dd HH:mm:ss.SSS";

    public static String DISPERSE = "yyyy MM dd HH mm ss";

    private static String[] parsePatterns = {
            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};


    /**
     * 获取当前Date型日期
     *
     * @return Date() 当前日期
     */
    public static Date getNowDate() {
        return new Date();
    }

    /**
     * 获取当前日期, 默认格式为yyyy-MM-dd
     *
     * @return String
     */
    public static String getDate() {
        return dateTimeNow(YYYY_MM_DD);
    }

    public static final String getTime() {
        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
    }

    public static final String dateTimeNow() {
        return dateTimeNow(YYYYMMDDHHMMSS);
    }

    public static final String dateTimeNow(final String format) {
        return parseDateToStr(format, new Date());
    }

    public static final String dateTime(final Date date) {
        return parseDateToStr(YYYY_MM_DD, date);
    }

    public static final String parseDateToStr(final String format, final Date date) {
        return new SimpleDateFormat(format).format(date);
    }

    public static final Date dateTime(final String format, final String ts) {
        try {
            return new SimpleDateFormat(format).parse(ts);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 日期路径 即年/月/日 如2018/08/08
     */
    public static final String datePath() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyy/MM/dd");
    }

    /**
     * 日期路径 即年/月/日 如20180808
     */
    public static final String dateTime() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyyMMdd");
    }

    /**
     * 日期型字符串转化为日期 格式
     */
    public static Date parseDate(Object str) {
        if (str == null) {
            return null;
        }
        try {
            return parseDate(str.toString(), parsePatterns);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 获取服务器启动时间
     */
    public static Date getServerStartDate() {
        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
        return new Date(time);
    }

    /**
     * 计算相差天数
     */
    public static int differentDaysByMillisecond(Date date1, Date date2) {
        return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
    }

    /**
     * 计算两个时间差
     */
    public static long getDatePoor(Date endDate, Date nowDate) {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        // long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;
        // 计算差多少秒//输出结果
        // long sec = diff % nd % nh % nm / ns;
        return min;
    }

    /**
     * 增加 LocalDateTime ==> Date
     */
    public static Date toDate(LocalDateTime temporalAccessor) {
        ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
        return Date.from(zdt.toInstant());
    }

    /**
     * 增加 LocalDate ==> Date
     */
    public static Date toDate(LocalDate temporalAccessor) {
        LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
        ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
        return Date.from(zdt.toInstant());
    }


    /**
     * Java时间戳转字符日期
     */
    public static String TimeStampCastToStrDate(Long time) {
        String dateStr = null;
        try {
            dateStr = new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS, Locale.CHINA).format(new Date(time));
            return dateStr;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Java时间戳转Date日期
     *
     * @param time
     * @return
     */
    public static Date TimeStampCastToDate(Integer time) {
        long tiems = Long.valueOf(time.toString() + "000");
        Date date = new Date(tiems);
        return date;
    }


    /**
     * Java日期转时间戳
     *
     * @param time
     * @return
     */
    public static Long DateToTimeStamp(String time) {
        SimpleDateFormat sdf = new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS);
        Date date = null;
        try {
            date = sdf.parse(time);
            return date.getTime();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将date转为LocalDateTIme
     *
     * @param date
     * @return
     */
    public static LocalDateTime DateCaseToLocalDateTime(Date date) {
        try {
            Instant instant = date.toInstant();
            LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
            return localDateTime;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 时间戳转为LocalDateTime
     *
     * @return
     */
    public static LocalDateTime TimeStampCastToLocalDateTime(Integer time) {
        Date date = TimeStampCastToDate(time);
        LocalDateTime localDateTime = DateCaseToLocalDateTime(date);
        return localDateTime;
    }

    /**
     * 计算两时间差（返回毫秒）
     */
    public static Long tr(LocalDateTime start, LocalDateTime end) {
        Duration duration = Duration.between(start, end);
        long l = duration.toMillis();
        return l;
    }

    /**
     * 计算两日期所差天数
     */
    public static Long days(LocalDateTime start, LocalDateTime end) {
        Duration duration = Duration.between(start, end);
        long l = duration.toDays();
        return l;
    }

    /**
     * 计算指定日期的零点时刻
     */
    public static Date zeroTime(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
        LocalDateTime startDay = localDateTime.with(LocalTime.MIN);
        return Date.from(startDay.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 计算指定日期减一个小时
     */
    public static Date subTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.HOUR, -1);
        Date time = calendar.getTime();
        return time;
    }

    /**
     * 延后3分钟
     *
     * @param date
     * @return
     */
    public static Date addMinute(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MINUTE, 3);
        return calendar.getTime();
    }

    /**
     * 延后1小时
     *
     * @param date
     * @return
     */
    public static Date addHour(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.HOUR_OF_DAY, 24);
        return calendar.getTime();
    }

    /**
     * 延迟15s
     */
    public static LocalDateTime validSec(String time, String speator) {
        Date date = DateUtilsCore.dateTime(DateUtilsCore.YYYY_MM_DD_HH_MM_SS, time);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        if (speator.equals("add")) {
            calendar.add(Calendar.SECOND, 15);
        }
        if (speator.equals("sub")) {
            calendar.add(Calendar.SECOND, -15);
        }
        Date afterTime = calendar.getTime();
        LocalDateTime localDateTime = DateCaseToLocalDateTime(afterTime);
        return localDateTime;
    }

    /**
     *
     */
    public static LocalDateTime strCastToLocalDateTime(String format, String time) {
        Date date = DateUtilsCore.dateTime(format, time);
        return DateCaseToLocalDateTime(date);
    }

    /**
     * String转LocalDateTime
     *
     * @param time
     * @return
     */
    public static LocalDateTime string2LocalDateTime(String time, String pattern) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
        LocalDateTime localDateTime = LocalDateTime.parse(time, dateTimeFormatter);
        return localDateTime;
    }

    public static Date string2LocalDate(String time, String pattern) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
        try {
            return simpleDateFormat.parse(time);
        } catch (ParseException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * LocalDateTime转String
     *
     * @param time
     * @return
     */
    public static String LocalDateTime2String(LocalDateTime time, String pattern) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
        String format = dateTimeFormatter.format(time);
        return format;
    }

    /**
     * String转Date
     *
     * @param time
     * @return
     */
    public static Date StringToDate(String s) {
        Date date = null;
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            date = dateFormat.parse(s);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

    /**
     * Date转String
     *
     * @param time
     * @return
     */
    public static String DateToString(Date date) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = dateFormat.format(date);
        return time;
    }

    /**
     * Date转String
     *
     * @param time
     * @return
     */
    public static String DateToStringBypa(Date date, String pa) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(pa);
        String time = dateFormat.format(date);
        return time;
    }

    /**
     * 计算天数
     *
     * @param time
     * @return
     */
    public static long getDay(String startTime, String endTime) {
        // 开始时间 String转LocalDayteTime 并获取零点
        LocalDateTime starDateTime = LocalDateTime.of(DateUtilsCore.string2LocalDateTime(startTime, DateUtilsCore.YYYY_MM_DD_HH_MM_SS).toLocalDate(), LocalTime.MIN);
        // 结束时间 String转LocalDateTime
        LocalDateTime endDateTime = DateUtilsCore.string2LocalDateTime(endTime, DateUtilsCore.YYYY_MM_DD_HH_MM_SS);
        // 判断结束时间是否为零点
        if (!endDateTime.equals(LocalDateTime.of(endDateTime.toLocalDate(), LocalTime.MIN))) {
            // 不是零点，则获取第二天零点
            endDateTime = LocalDateTime.of(endDateTime.plusDays(1).toLocalDate(), LocalTime.MIN);
        }
        // 开始时间和结束时间相差天数
        long difference = Duration.between(starDateTime, endDateTime).toDays();
        return difference;
    }

    /**
     * 按照天数 分割时间
     *
     * @param time
     * @return
     */
    public static List<Map<String, String>> splitDateByDay(String startTime, String endTime, long daysum) {
        LocalDateTime startDateTime = string2LocalDateTime(startTime, YYYY_MM_DD_HH_MM_SS);
        LocalDateTime endDateTime = string2LocalDateTime(endTime, YYYY_MM_DD_HH_MM_SS);
        List<Map<String, String>> dayList = new ArrayList<>();
        Duration between = Duration.between(startDateTime, endDateTime);
        long betweenDay = between.toDays();
        for (long i = 0; i <= betweenDay; i = i + daysum) {
            HashMap<String, String> map = new HashMap<>();
            LocalDateTime startDateTimenew = LocalDateTime.of(startDateTime.toLocalDate(), LocalTime.MIN).plusDays(i);
            LocalDateTime endDateTimenew = LocalDateTime.of(startDateTimenew.plusDays(daysum).toLocalDate(), LocalTime.MAX);
            String startTimen = LocalDateTime2String(startDateTimenew, YYYY_MM_DD_HH_MM_SS);
            String endTimen = LocalDateTime2String(endDateTimenew, YYYY_MM_DD_HH_MM_SS);
            if (i == 0) {
                map.put("startTime", startTime);
            } else {
                map.put("startTime", startTimen);
            }
            map.put("endTime", endTimen);
            if (Duration.between(endDateTimenew, endDateTime).toDays() < 0) {
                endDateTimenew = endDateTime;
                endTimen = LocalDateTime2String(endDateTimenew, YYYY_MM_DD_HH_MM_SS);
                map.put("endTime", endTimen);
            }
            dayList.add(map);
        }
        return dayList;
    }


    public static List<Map<String, String>> splitDateByDay(String startTime, String endTime) {

        List<Map<String, String>> dayList = new ArrayList<>();

        LocalDateTime startDateTime = string2LocalDateTime(startTime, YYYY_MM_DD_HH_MM_SS);
        LocalDateTime endDateTime = string2LocalDateTime(endTime, YYYY_MM_DD_HH_MM_SS);

        //  判断相差天数
        Duration between = Duration.between(startDateTime, endDateTime);
        long betweenDay = between.toDays();

        //  如果同天
        if (betweenDay == 0) {
            HashMap<String, String> map = new HashMap<>();
            map.put("startTime", startTime);
            map.put("endTime", endTime);
            dayList.add(map);
            return dayList;
        }

        // 如果跨一天
        if (betweenDay == 1) {
            HashMap<String, String> map = new HashMap<>();
            map.put("startTime", startTime);
            LocalDateTime endDateTimenew = LocalDateTime.of(startDateTime.toLocalDate(), LocalTime.MAX);
            String endTimen = LocalDateTime2String(endDateTimenew, YYYY_MM_DD_HH_MM_SS);
            map.put("endTime", endTimen);
            dayList.add(map);

            HashMap<String, String> map1 = new HashMap<>();

            LocalDateTime startTimea = LocalDateTime.of(endDateTime.toLocalDate(), LocalTime.MIN);
            String stringa = LocalDateTime2String(startTimea, YYYY_MM_DD_HH_MM_SS);

            map1.put("startTime", stringa);
            map1.put("endTime", endTime);
            dayList.add(map1);
            return dayList;
        }

        //  如果跨多天
        if (betweenDay > 1) {
            for (int i = 0; i < betweenDay + 1; i++) {
                HashMap<String, String> map = new HashMap<>();
                LocalDateTime startDateTimenew = LocalDateTime.of(startDateTime.toLocalDate(), LocalTime.MIN).plusDays(i);
                String stringa = LocalDateTime2String(startDateTimenew, YYYY_MM_DD_HH_MM_SS);
                LocalDateTime endDateTimenew = LocalDateTime.of(startDateTime.toLocalDate(), LocalTime.MAX).plusDays(i);
                map.put("startTime", stringa);
                map.put("endTime", LocalDateTime2String(endDateTimenew, YYYY_MM_DD_HH_MM_SS));
                dayList.add(map);
            }
        }

        dayList.get(0).put("startTime", startTime);
        dayList.get(dayList.size() - 1).put("endTime", endTime);
        return dayList;
    }

    /**
     * 根据开始时间和结束时间观测日期是否一致
     *
     * @param starttime
     * @param endtime
     * @return
     */
    public static List<String> getDBtableDate(String starttime, String endtime) {
        String startdate = starttime.substring(0, 4) + starttime.substring(5, 7);
        String enddate = endtime.substring(0, 4) + endtime.substring(5, 7);
        List<String> tabledate = new ArrayList<String>();
        tabledate.add(startdate);
        if (!startdate.equalsIgnoreCase(enddate)) {
            tabledate.add(enddate);
        }
        return tabledate;
    }

    /**
     * 将yyyy-MM-ddTHH:mm:ss.UUU格式的字符串转换为Calendar类型
     *
     * @param calendarString
     * @return
     */
    public static Calendar stringToCalendar(String calendarString) {
        if (calendarString == null || calendarString.trim().length() == 0) {
            return null;
        }
        String dateStr = calendarString;
        if (calendarString.trim().indexOf("T") != -1) {
            dateStr = calendarString.trim().replace("T", " ");
        }
        String dateFormat = "yyyy-MM-dd HH:mm:ss";
        if (dateStr.indexOf(".") != -1) {
            dateFormat += ".SSS";
        }
        SimpleDateFormat formatter = new SimpleDateFormat(dateFormat);
        Calendar calendar = Calendar.getInstance();
        try {
            calendar.setTime(formatter.parse(dateStr));
        } catch (ParseException e) {
            return null;
        }
        return calendar;
    }

    /**
     * 时间戳转Date日期
     *
     * @param strTime 字符时间戳
     * @return
     */
    public static Date strCastToDate(String strTime) {
        if (StringUtils.isNotEmpty(strTime)) {
            Date date = DateUtilsCore.string2LocalDate(DateUtilsCore.TimeStampCastToStrDate(Long.valueOf(strTime)), DateUtilsCore.YYYY_MM_DD_HH_MM_SS);
            return date;
        }
        return null;
    }


    /**
     * 取中间时刻
     *
     * @param ObservationStartTime
     * @param ObservationEndTime
     * @return
     */
    public static Date getMiddleTime(Date ObservationStartTime, Date ObservationEndTime) {
        if (Objects.nonNull(ObservationStartTime) && Objects.nonNull(ObservationEndTime)) {
            long middleTime = (ObservationStartTime.getTime() + ObservationEndTime.getTime()) / 2;
            return new Date(middleTime);
        }
        return null;

    }

    public static void DateListSort(List<Date> list,String type){
        Collections.sort(list, new Comparator<Date>() {
            @Override
            public int compare(Date o1, Date o2) {
                if (type.equals("asc")){
                    if (o1.getTime()>o2.getTime()){
                        return 1;
                    }else if (o1.getTime()<o2.getTime()){
                        return -1;
                    }
                }else if (type.equals("desc")){
                    if (o1.getTime()<o2.getTime()){
                        return 1;
                    }else if (o1.getTime()>o2.getTime()){
                        return -1;
                    }
                }
                return 0;
            }
        });
    }
}

