package vip.xiaonuo.common.util;

import cn.hutool.core.date.DateUtil;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 日期工具
 *
 * @author xiang
 * @date 2023/03/08 16:49
 **/
public class DatesUtil {

    /**
     * 获取范围开始的时间
     *
     * @param type 1、当日；2、本周；3、本月；4、季度；5、年度
     */
    public static Date getStartTime(Date date, int type) {
        Date result = null;
        if (type == 1)
            result = DateUtil.beginOfDay(date);
        else if (type == 2)
            result = DateUtil.beginOfWeek(date);
        else if (type == 3)
            result = DateUtil.beginOfMonth(date);
        else if (type == 4)
            result = DateUtil.beginOfQuarter(date);
        else if (type == 5)
            result = DateUtil.beginOfYear(date);
        return result;
    }

    /**
     * 获取范围开始的时间
     *
     * @param type 1、当日；2、本周；3、本月；4、季度；5、年度
     */
    public static String getStartTime(String date, int type) {
        return DatesUtil.forDateTime(getStartTime(DatesUtil.forDate(date), type));
    }

    /**
     * 获取范围结束的时间
     *
     * @param type 1、当日；2、本周；3、本月；4、季度；5、年度
     */
    public static String getEndTime(String date, int type) {
        return DatesUtil.forDateTime(getEndTime(DatesUtil.forDate(date), type));
    }

    /**
     * 获取范围结束的时间
     *
     * @param type 1、当日；2、本周；3、本月；4、季度；5、年度
     */
    public static Date getEndTime(Date date, int type) {
        Date result = null;
        if (type == 1)
            result = DateUtil.endOfDay(date);
        else if (type == 2)
            result = DateUtil.endOfWeek(date);
        else if (type == 3)
            result = DateUtil.endOfMonth(date);
        else if (type == 4)
            result = DateUtil.endOfQuarter(date);
        else if (type == 5)
            result = DateUtil.endOfYear(date);
        return result;
    }

    /**
     * 根据传入的字符串时间格式化日期
     *
     * @param str
     * @return dateTime
     */
    public static Date forDateTime(String str) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date dateTime = null;
        try {
            dateTime = sdf.parse(str);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return dateTime;
    }

    /**
     * 日时格式化
     *
     * @return 2002-02-02 01:30
     * @author xiang
     * @date 2023/3/20 18:00
     **/
    public static String forDateTime16(Date date) {
        if (date == null)
            date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        return sdf.format(date);
    }

    /**
     * 日时格式化
     *
     * @return 2002-02-02 01:30
     * @author xiang
     * @date 2023/3/20 18:00
     **/
    public static String forDateTime14(Date date) {
        if (date == null)
            date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd HH:mm");
        return sdf.format(date);
    }

    /**
     * 日时格式化
     *
     * @return 2002-02-02 01:30
     * @author xiang
     * @date 2023/3/20 18:00
     **/
    public static String forDateTimeAll14() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        return sdf.format(date);
    }

    /**
     * 日时格式化
     *
     * @return 2002-02-02 01:30
     * @author xiang
     * @date 2023/3/20 18:00
     **/
    public static String forDateTimeAll17() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        return sdf.format(date);
    }

    /**
     * 日时格式化
     *
     * @return 2002-02-02 01:30
     * @author xiang
     * @date 2023/3/20 18:00
     **/
    public static String forDateTimeAll10() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHH");
        return sdf.format(date);
    }

    /**
     * 日时格式化
     *
     * @return 2002-02-02 01:30:10
     * @author xiang
     * @date 2023/3/20 18:00
     **/
    public static String forDateTime(Date date) {
        if (date == null)
            date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }

    /**
     * 日时格式化
     *
     * @return 2002-02-02 01:30:10
     * @author xiang
     * @date 2023/3/20 18:00
     **/
    public static String forDateTime() {
        return DatesUtil.forDateTime(new Date());
    }

    /**
     * 日时格式化
     *
     * @return 2002-02-02 01:30:10
     * @author xiang
     * @date 2023/3/20 18:00
     **/
    public static Date forDate(String str) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date dateTime = null;
        try {
            dateTime = sdf.parse(str);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return dateTime;
    }

    /**
     * 日期格式化
     *
     * @return 2002-02-02
     * @author xiang
     * @date 2023/3/20 18:00
     **/
    public static String forDate(Date date) {
        if (date == null)
            date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(date);
    }

    /**
     * 日期格式化
     *
     * @return 2002-02-02
     * @author xiang
     * @date 2023/3/20 18:00
     **/
    public static String forDate() {
        return DatesUtil.forDate(new Date());
    }

    /**
     * 是过去
     *
     * @return true
     * @author xiang
     * @date 2023/3/20 18:00
     **/
    public static boolean overTimeFlag(Date date) {
        return date == null ? false : date.compareTo(new Date()) < 0;
    }

    /**
     * 加上分钟数
     *
     * @return 小时数
     * @author xiang
     * @date 2023/3/20 18:00
     **/
    public static Date addMinute(Date date, int minute) {
        Date result = date == null ? new Date() : (Date) date.clone();
        result.setMinutes(result.getMinutes() + minute);
        return result;
    }

    /**
     * 加上小时数
     *
     * @return 小时数
     * @author xiang
     * @date 2023/3/20 18:00
     **/
    public static Date addHour(Date date, BigDecimal hour) {
        Date result = (Date) date.clone();
        result.setMinutes(date.getMinutes() + hour.multiply(new BigDecimal(60)).intValue());
        return result;
    }

    /**
     * 加上小时数
     *
     * @return 小时数
     * @author xiang
     * @date 2023/3/20 18:00
     **/
    public static String addHour(String dateTime, BigDecimal hour) {
        return DatesUtil.forDateTime(DatesUtil.addHour(DatesUtil.forDateTime(dateTime), hour));
    }

    /**
     * 加上小时数
     *
     * @return 小时数
     * @author xiang
     * @date 2023/3/20 18:00
     **/
    public static String addHour(String dateTime, int hour) {
        return DatesUtil.forDateTime(DatesUtil.addHour(DatesUtil.forDateTime(dateTime), new BigDecimal(hour)));
    }

    /**
     * 加上天数
     *
     * @return 小时数
     * @author xiang
     * @date 2023/3/20 18:00
     **/
    public static String addDay(String dateTime, int count) {
        return DatesUtil.forDate(DatesUtil.addHour(DatesUtil.forDate(dateTime), new BigDecimal(count * 24)));
    }

    /**
     * 加上天数
     *
     * @return 小时数
     * @author xiang
     * @date 2023/3/20 18:00
     **/
    public static Date addDay(Date dateTime, int count) {
        return DatesUtil.addHour(dateTime, new BigDecimal(count * 24));
    }

    /**
     * 相差分钟
     *
     * @return 小时数
     * @author xiang
     * @date 2023/3/20 18:00
     **/
    /*public static int minuteCount(Date sDate, Date eDate) {
        return BigDecimalUtil.divide(new BigDecimal(Math.toIntExact(eDate.getTime() - sDate.getTime())), new BigDecimal(1000 * 60), 0, BigDecimal.ROUND_CEILING).intValue();
    }*/

    /**
     * 相差小时数
     *
     * @return 小时数
     * @author xiang
     * @date 2023/3/20 18:00
     **/
    public static double hourCount(String sDate, String eDate) {
        return Math.toIntExact(DatesUtil.forDateTime(eDate).getTime() - DatesUtil.forDateTime(sDate).getTime()) / (1000 * 60 * 60 * 1.0);
    }

    /**
     * 相差小时数
     *
     * @return 小时数
     * @author xiang
     * @date 2023/3/20 18:00
     **/
    public static double hourCount(Date s_date, Date e_date) {
        return Math.toIntExact(e_date.getTime() - s_date.getTime()) / (1000 * 60 * 60 * 1.0);
    }

    /**
     * 获取两个日期之间的所有整点和半点
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return 集合(2023 - 05 - 18 18 : 00, 2023 - 05 - 18 18 : 30)
     */
    public static List<String> hourMinuteBetween(Date startDate, Date endDate) {
        int hour = (int) DatesUtil.hourCount(startDate, endDate);
        List<String> list = new ArrayList<>();
        int startHour = startDate.getHours();
        for (int i = startHour; i < startHour + hour; i++) {
            Date startTime = (Date) startDate.clone();
            startTime.setHours(i);
            String date = DatesUtil.forDate(startTime) + " ";
            list.add(date + DatesUtil.forJiDian(i, 0));
            list.add(date + DatesUtil.forJiDian(i, 30));
        }
        //删除最后两条
        return list.stream().distinct().collect(Collectors.toList());
    }

    /**
     * 获取两个日期之间的所有日期
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return List集合
     */
    public static List<String> dateBetween(Date startDate, Date endDate) {
        Date sDate = new Date(startDate.getTime());
        List<String> list = new ArrayList<>();
        while (sDate.compareTo(endDate) < 1) {
            list.add(DatesUtil.forDate(sDate));
            sDate.setHours(24);
        }
        return list;
    }

    /**
     * 获取两个日期之间的所有日期
     *
     * @param s_date 开始日期
     * @param e_date 结束日期
     * @param length 日期转换长度 4:年,7:月,10/19:日
     * @return List集合
     */
    public static List<String> dateBetween(String s_date, String e_date, int length) {
        List<String> result = new ArrayList<>();
        //年
        if (length == 4) {
            int startYear = Integer.parseInt(s_date.substring(0, 4));
            int endYear = Integer.parseInt(e_date.substring(0, 4));
            for (int i = 0; i < endYear - startYear + 1; i++) {
                result.add(String.valueOf(startYear + i));
            }
        }
        //月
        else if (length == 7) {
            List<String> dateLst = DatesUtil.dateBetween(DatesUtil.forDate(s_date), DatesUtil.forDate(e_date));
            result = dateLst.stream().map(m -> m.substring(0, 7)).distinct().collect(Collectors.toList());
        }
        //日
        else if (length == 10) {
            result = DatesUtil.dateBetween(DatesUtil.forDate(s_date), DatesUtil.forDate(e_date));
        }
        //时
        else if (length == 13) {
            List<String> timeResult = new ArrayList<>(result.size() * 24);
            result = DatesUtil.dateBetween(DatesUtil.forDate(s_date), DatesUtil.forDate(e_date));
            result.forEach(r -> {
                timeResult.add(r + " 00");
                timeResult.add(r + " 01");
                timeResult.add(r + " 02");
                timeResult.add(r + " 03");
                timeResult.add(r + " 04");
                timeResult.add(r + " 05");
                timeResult.add(r + " 06");
                timeResult.add(r + " 07");
                timeResult.add(r + " 08");
                timeResult.add(r + " 09");
                timeResult.add(r + " 10");
                timeResult.add(r + " 11");
                timeResult.add(r + " 12");
                timeResult.add(r + " 13");
                timeResult.add(r + " 14");
                timeResult.add(r + " 15");
                timeResult.add(r + " 16");
                timeResult.add(r + " 17");
                timeResult.add(r + " 18");
                timeResult.add(r + " 19");
                timeResult.add(r + " 20");
                timeResult.add(r + " 21");
                timeResult.add(r + " 22");
                timeResult.add(r + " 23");
            });
            return timeResult;
        }
        return result;
    }

    /**
     * 获取两个日期之间的所有周期
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return 集合(5, 6, 7)
     */
    public static List<String> weekBetween(Date startDate, Date endDate) {
        Date sDate = new Date(startDate.getTime());
        List<String> list = new ArrayList<>();
        while (sDate.compareTo(endDate) < 1) {
            list.add(String.valueOf(sDate.getDay()));
            sDate.setHours(24);
        }
        return list.stream().distinct().collect(Collectors.toList());
    }

    /**
     * 在两个两个日期之间
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return boolean
     */
    public static boolean dateBetween(Date date, Date startDate, Date endDate) {
        if (date == null || startDate == null || endDate == null)
            return false;
        return startDate.compareTo(date) < 1 && endDate.compareTo(date) > -1;
    }

    /***
     * 两段日期是否有交集
     * 其中一个结束日可以为空
     * @param startDateOne  开始日一
     * @param endDateOne    结束日一
     * @param startDateTwo  开始日二
     * @param endDateTwo    结束日二
     * @return 交集true
     */
    public static Boolean isInterSection(Date startDateOne, Date endDateOne, Date startDateTwo, Date endDateTwo) {
        if (endDateOne == null)
            return startDateOne.compareTo(startDateTwo) > -1 && startDateOne.compareTo(endDateTwo) < 1;
        if (endDateTwo == null)
            return startDateTwo.compareTo(startDateOne) > -1 && startDateTwo.compareTo(endDateOne) < 1;
        Date maxStartDate = startDateOne;
        if (maxStartDate.before(startDateTwo))
            maxStartDate = startDateTwo;
        Date minEndDate = endDateOne;
        if (endDateTwo.before(minEndDate))
            minEndDate = endDateTwo;
        return maxStartDate.compareTo(minEndDate) < 1;
    }

    /**
     * 拼接完整日期
     *
     * @param date       日期
     * @param hourMinute 时分
     * @return 01:30
     * @author xiang
     * @date 2023/3/11 18:00:00
     **/
    public static String forDateTime(String date, String hourMinute) {
        return StringUtils.join(date, " ", hourMinute, ":00");
    }

    /**
     * 获取时分格式化
     *
     * @return 01:30
     * @author xiang
     * @date 2023/3/11 18:00
     **/
    public static String forJiDian(Date date) {
        return DatesUtil.forJiDian(date.getHours(), date.getMinutes());
    }

    /**
     * 获取时分格式化
     *
     * @return 01:30
     * @author xiang
     * @date 2023/3/11 18:00
     **/
    public static String forJiDian(int h, int m) {
        return StringUtils.join(String.format("%02d", h % 24), ":", String.format("%02d", m));
    }

    /**
     * 相差天数
     *
     * @param date1 开始时间
     * @param date2 结束时间
     * @return 天数
     */
    public static int differentDaysByMillisecond(String date1, String date2) {
        Long dates = (DatesUtil.forDate(date2).getTime() - DatesUtil.forDate(date1).getTime()) / 1000 / 3600 / 24;
        return dates.intValue();
    }

    public static void main(String[] args) {

    }

}
