package com.skua.tool.util;

import com.skua.constant.BaseConstant;

import java.math.BigDecimal;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * <pre>
 * 日期工具类
 * </pre>
 *
 * @author sonin
 * @version 1.0 2022/4/20 17:22
 */
public class DateUtils {

    /**
     * 根据(开始时间, 结束时间)获取每一个时间间隔的数据, 主要用于eCharts图标xData
     *
     * @param startTime
     * @param endTime
     * @param format
     * @return
     */
    public static List<String> interval(String startTime, String endTime, String format, int field, int amount) {
        List<String> intervalList = new ArrayList<>();
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
            Date startDate = simpleDateFormat.parse(startTime);
            Date endDate = simpleDateFormat.parse(endTime);
            List<Date> dateList = new ArrayList<>();
            dateList.add(startDate);
            Calendar calendarOfStart = Calendar.getInstance();
            // 使用给定的 Date 设置此 Calendar 的时间
            calendarOfStart.setTime(startDate);
            Calendar calendarOfEnd = Calendar.getInstance();
            // 使用给定的 Date 设置此 Calendar 的时间
            calendarOfEnd.setTime(endDate);
            // 测试此日期是否在指定日期之后
            while (endDate.compareTo(calendarOfStart.getTime()) >= 0) {
                // 根据日历的规则,为给定的日历字段添加或减去指定的时间量
                calendarOfStart.add(field, amount);
                if (endDate.compareTo(calendarOfStart.getTime()) >= 0 && !dateList.contains(calendarOfStart.getTime())) {
                    dateList.add(calendarOfStart.getTime());
                }
            }
            for (Date item : dateList) {
                intervalList.add(simpleDateFormat.format(item));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return intervalList;
    }

    public static List<String> intervalByHour(String startTime, String endTime, String format) {
        return interval(startTime, endTime, format, Calendar.HOUR_OF_DAY, 1);
    }

    public static List<String> intervalByDay(String startTime, String endTime, String format) {
        return interval(startTime, endTime, format, Calendar.DAY_OF_MONTH, 1);
    }

    public static List<String> intervalByMonth(String startTime, String endTime, String format) {
        return interval(startTime, endTime, format, Calendar.MONTH, 1);
    }

    public static List<String> intervalByYear(String startTime, String endTime, String format) {
        return interval(startTime, endTime, format, Calendar.YEAR, 1);
    }

    /**
     * 根据某个时间获取前多少天,或者后多少天
     *
     * @param dateTime yyyy-MM-dd
     * @param limit    天数
     * @return
     */
    public static List<String> increaseDay(String dateTime, int limit) {
        return stepDay(dateTime, limit, true);
    }

    /**
     * 根据某个时间获取前多少天,或者后多少天
     *
     * @param dateTime yyyy-MM-dd
     * @param limit    天数
     * @return
     */
    public static List<String> decreaseDay(String dateTime, int limit) {
        return stepDay(dateTime, limit, false);
    }

    private static List<String> stepDay(String dateTime, int limit, boolean flag) {
        LinkedList<String> dateList = new LinkedList<>();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        int factor = 1;
        if (!flag) {
            factor = -1;
        }
        for (int i = 0; i < limit; i++) {
            Date date = simpleDateFormat.parse(dateTime, new ParsePosition(0));
            calendar.setTime(date);
            calendar.add(Calendar.DATE, factor * i);
            if (flag) {
                dateList.addLast(simpleDateFormat.format(calendar.getTime()));
            } else {
                dateList.addFirst(simpleDateFormat.format(calendar.getTime()));
            }
        }
        return dateList;
    }


    /**
     * <pre>
     * 根据某个日期获取指定时间
     * </pre>
     *
     * @param currentDate
     * @param field:      Calendar.DATE、Calendar.MONTH ...
     * @param step:       step>0获取往后某一天,step<0获取之前某一天
     * @author sonin
     * @Description: TODO(这里描述这个方法的需求变更情况)
     */
    public static Date someDate(Date currentDate, Integer field, Integer step) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(currentDate);
        calendar.add(field, step);
        return calendar.getTime();
    }

    /**
     * <pre>
     * 昨天此刻
     * </pre>
     *
     * @param currentDate
     * @author sonin
     * @Description: TODO(这里描述这个方法的需求变更情况)
     */
    public static Date prevDay(Date currentDate) {
        return someDate(currentDate, Calendar.DATE, -1);
    }

    /**
     * <pre>
     * 上个月此刻
     * </pre>
     *
     * @param currentDate
     * @author sonin
     * @Description: TODO(这里描述这个方法的需求变更情况)
     */
    public static Date prevMonth(Date currentDate) {
        return someDate(currentDate, Calendar.MONTH, -1);
    }

    /**
     * <pre>
     * 去年此刻
     * </pre>
     *
     * @param currentDate
     * @author sonin
     * @Description: TODO(这里描述这个方法的需求变更情况)
     */
    public static Date prevYear(Date currentDate) {
        return someDate(currentDate, Calendar.YEAR, -1);
    }

    /**
     * <pre>
     * 明天此刻
     * </pre>
     *
     * @param currentDate
     * @author sonin
     * @Description: TODO(这里描述这个方法的需求变更情况)
     */
    public static Date nextDay(Date currentDate) {
        return someDate(currentDate, Calendar.DATE, 1);
    }

    /**
     * <pre>
     * 下个月此刻
     * </pre>
     *
     * @param currentDate
     * @author sonin
     * @Description: TODO(这里描述这个方法的需求变更情况)
     */
    public static Date nextMonth(Date currentDate) {
        return someDate(currentDate, Calendar.MONTH, 1);
    }

    /**
     * <pre>
     * 明年此刻
     * </pre>
     *
     * @param currentDate
     * @author sonin
     * @Description: TODO(这里描述这个方法的需求变更情况)
     */
    public static Date nextYear(Date currentDate) {
        return someDate(currentDate, Calendar.YEAR, 1);
    }

    /**
     * <pre>
     * 获取某一周: 0:这周; -1:上一周; 1:下一周;
     * </pre>
     *
     * @param
     * @author sonin
     * @Description: TODO(这里描述这个方法的需求变更情况)
     */
    public static List<String> someWeek(int n) {
        String format = "yyyy-MM-dd";
        LocalDateTime now = LocalDateTime.now();
        // 获取本周
        DayOfWeek dayOfWeek = now.getDayOfWeek();
        // 本周周一
        String startTime = now.minusDays(dayOfWeek.getValue() - 1).format(DateTimeFormatter.ofPattern(format));
        // 本周周日
        String endTime = now.plusDays(7 - dayOfWeek.getValue()).format(DateTimeFormatter.ofPattern(format));
        if (n != 0) {
            startTime = date2Str(someDate(strToDate(startTime, format), Calendar.DATE, n * 7), format);
            endTime = date2Str(someDate(strToDate(endTime, format), Calendar.DATE, n * 7), format);
        }
        return intervalByDay(startTime, endTime, format);
    }

    /**
     * <pre>
     * 获取某一个月: 0:这个月; -1:上一月; 1:下一月;
     * </pre>
     *
     * @param
     * @author sonin
     * @Description: TODO(这里描述这个方法的需求变更情况)
     */
    public static List<String> someMonth(int n) {
        Date date = someDate(new Date(), Calendar.MONTH, n);
        Calendar calendar = Calendar.getInstance(Locale.CHINA);
        calendar.setTime(date);
        int year = calendar.get(Calendar.YEAR); //年份
        int month = calendar.get(Calendar.MONTH) + 1; //月份
        int day = calendar.getActualMaximum(Calendar.DATE); // 天数
        String startTime = year + "-" + (month < 10 ? ("0" + month) : month) + "-01";
        String endTime = year + "-" + (month < 10 ? ("0" + month) : month) + "-" + day;
        return intervalByDay(startTime, endTime, "yyyy-MM-dd");
    }

    /**
     * <pre>
     * 获取指定某一个月: 0:这个月; -1:上一月; 1:下一月;
     * </pre>
     *
     * @param currentDate
     * @param n
     * @author sonin
     * @Description: TODO(这里描述这个方法的需求变更情况)
     */
    public static List<String> someMonth(Date currentDate, int n) {
        Date date = someDate(currentDate, Calendar.MONTH, n);
        Calendar calendar = Calendar.getInstance(Locale.CHINA);
        calendar.setTime(date);
        int year = calendar.get(Calendar.YEAR); //年份
        int month = calendar.get(Calendar.MONTH) + 1; //月份
        int day = calendar.getActualMaximum(Calendar.DATE); // 天数
        String startTime = year + "-" + (month < 10 ? ("0" + month) : month) + "-01";
        String endTime = year + "-" + (month < 10 ? ("0" + month) : month) + "-" + day;
        return intervalByDay(startTime, endTime, "yyyy-MM-dd");
    }

    /**
     * String => java.util.Date
     *
     * @param str        表示日期的字符串
     * @param dateFormat 传入字符串的日期表示格式(如:"yyyy-MM-dd HH:mm:ss")
     * @return java.util.Date类型日期对象(如果转换失败则返回null)
     */
    public static Date strToDate(String str, String dateFormat) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
        Date date = null;
        try {
            date = simpleDateFormat.parse(str);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return date;
    }

    /**
     * <pre>
     *  java.util.Date => String
     * </pre>
     *
     * @param date
     * @param format
     * @author sonin
     * @Description: TODO(这里描述这个方法的需求变更情况)
     */
    public static String date2Str(Date date, String format) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
        return simpleDateFormat.format(date);
    }

    public static String date2Str(Date date, SimpleDateFormat date_sdf) {
        return null == date ? null : date_sdf.format(date);
    }

    /**
     * <pre>
     * 日期字符串转秒
     * e.g: 2023-06-20 12:00:00 => 1687233600
     * </pre>
     *
     * @param dateStr
     * @param format
     * @author sonin
     * @Description: TODO(这里描述这个方法的需求变更情况)
     */
    public static Long dateStr2Sec(String dateStr, String format) {
        try {
            return new SimpleDateFormat(format).parse(dateStr).getTime() / 1000;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * <pre>
     * 秒转日期字符串
     * e.g: 1687233600 => 2023-06-20 12:00:00
     * </pre>
     *
     * @param sec
     * @param format
     * @author sonin
     * @Description: TODO(这里描述这个方法的需求变更情况)
     */
    public static String sec2DateStr(long sec, String format) {
        return new SimpleDateFormat(format).format(new Date(sec * 1000));
    }

    /**
     * <pre>
     * 获取最近月份集合
     * </pre>
     *
     * @param
     * @author sonin
     * @Description: TODO(这里描述这个方法的需求变更情况)
     */
    public static List<String> recentMonthList(int n) {
        List<String> yearMonthList = new ArrayList<>();
        Calendar calendar = Calendar.getInstance();
        // 1号就从上个月开始算
        int num = 1;
        // 判断今天是否是1号
        calendar.setTime(new Date());
        calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) + 1);
        if (calendar.get(Calendar.DAY_OF_MONTH) == 2) {
            num = 0;
        }
        calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) + num);
        for (int i = n - 1; i >= 0; i--) {
            // 1个月前
            calendar.add(Calendar.MONTH, -1);
            int month = calendar.get(Calendar.MONTH) + 1;
            String yearMonth = calendar.get(Calendar.YEAR) + "-" + (month < 10 ? ("0" + month) : ("" + month));
            yearMonthList.add(yearMonth);
        }
        return yearMonthList;
    }

    /**
     * <pre>
     * 获取同比时间
     * startTime与endTime不能超过一年
     * </pre>
     *
     * @param startTime
     * @param endTime
     * @author sonin
     * @Description: TODO(这里描述这个方法的需求变更情况)
     */
    public static String[] tbTime(String startTime, String endTime) {
        String yyyyOfStart = startTime.split("-")[0];
        String yyyyOfEnd = endTime.split("-")[0];
        String yyyyOfPrevStart = "" + (Integer.parseInt(yyyyOfStart) - 1);
        String yyyyOfPrevEnd = "" + (Integer.parseInt(yyyyOfEnd) - 1);
        return new String[]{startTime.replaceFirst(yyyyOfStart, yyyyOfPrevStart), endTime.replaceFirst(yyyyOfEnd, yyyyOfPrevEnd)};
    }

    /**
     * <pre>
     * 某个月的天数
     * </pre>
     *
     * @param year
     * @param month
     * @author sonin
     * @Description: TODO(这里描述这个方法的需求变更情况)
     */
    public static int lengthOfSomeMonth(int year, int month) {
        return YearMonth.of(year, month).lengthOfMonth();
    }

    public static String secToTime(String secondStr) {
        long second = new BigDecimal(secondStr).longValue();
        long a = second / 3600;
        long b = second % 3600;
        long c = b / 60;
        long d = b % 60;
        return (a < 10 ? ("0" + a) : a) + ":" + (c < 10 ? ("0" + c) : c) + ":" + (d < 10 ? ("0" + d) : d);
    }

    public static String sec2Day(String secondStr) {
        long second = new BigDecimal(secondStr).longValue();
        long a = second / (3600 * 24);
        long b = (second % (3600 * 24)) / 3600;
        return a + "天" + b + "小时";
    }

    /**
     * <pre>
     * 获取环比时间
     * </pre>
     *
     * @param startTime
     * @param endTime
     * @author sonin
     * @Description: TODO(这里描述这个方法的需求变更情况)
     */
    public static String[] hbTime(String startTime, String endTime) {
        String hbStartTime = DateUtils.date2Str(DateUtils.prevMonth(DateUtils.strToDate(startTime, BaseConstant.dateFormat)), BaseConstant.dateFormat);
        String hbEndTime = DateUtils.date2Str(DateUtils.prevMonth(DateUtils.strToDate(endTime, BaseConstant.dateFormat)), BaseConstant.dateFormat);
        while (!hbStartTime.split("-")[1].equals(hbEndTime.split("-")[1])) {
            hbEndTime = DateUtils.date2Str(DateUtils.prevDay(DateUtils.strToDate(hbEndTime, BaseConstant.dateFormat)), BaseConstant.dateFormat);
        }
        return new String[]{hbStartTime, hbEndTime};
    }

    /**
     * 同比
     * @param month
     * @return
     */
    public static String getTbMonth(String month) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
        YearMonth yearMonth = YearMonth.parse(month, formatter);
        YearMonth sameMonthLastYear = yearMonth.minusYears(1);
        return sameMonthLastYear.format(formatter);   // 同比
    }

    /**
     * 环比
     * @param month
     * @return
     */
    public static String getHbMonth(String month) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
        YearMonth yearMonth = YearMonth.parse(month, formatter);
        YearMonth previousMonth = yearMonth.minusMonths(1);
        return previousMonth.format(formatter);      // 环比
    }

    /**
     * 获取同比时间
     * @param date
     * @return
     */
    public static String getTbDate(String date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        try{
            Date dateTime = sdf.parse(date);
            calendar.setTime(dateTime);
        }catch (Exception e){
            calendar.setTime(new Date());
        }
        calendar.add(Calendar.YEAR, -1);
        Date preDate = calendar.getTime();
        return sdf.format(preDate);
    }

    /**
     * 获取环比时间
     * @param date
     * @return
     */
    public static String getHbDate(String date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        try{
            Date dateTime = sdf.parse(date);
            calendar.setTime(dateTime);
        }catch (Exception e){
            calendar.setTime(new Date());
        }
        calendar.add(Calendar.MONTH, -1);
        Date preDate = calendar.getTime();
        return sdf.format(preDate);
    }

}