
package com.tmerclub.cloud.common.util;

import cn.hutool.core.date.DateUtil;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.vo.DateVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 时间工具类
 * @author lhd
 */
public class DateUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(DateUtils.class);
    public static final int MONTHS = 12;
    public static final int LAST_HOUR = 23;
    public static final int LAST_MIN = 59;
    public static final int MAX_MILLISECOND = 999;

    public static Long dateToNumber(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String format = sdf.format(date);
        long value = 0L;
        try {
            value = Long.parseLong(format);
        } catch (Exception e) {
            return value;
        }
        return value;
    }

    public static String dateToStrYmd(Date date) {
        String format = "yyyy-MM-dd";
        return DateUtil.format(date, format);
    }

    public static List<Date> findDates(Date dBegin, Date dEnd) {
        List<Date> lDate = new ArrayList<>(Constant.INITIAL_CAPACITY);
        lDate.add(dBegin);
        Calendar cBegin = Calendar.getInstance();
        Calendar cEnd = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        cBegin.setTime(dBegin);
        cEnd.setTime(dEnd);

        cEnd.add(Calendar.DAY_OF_MONTH, -2);
        // 测试此日期是否在指定日期之后
        while (cEnd.getTime().after(cBegin.getTime())) {
            // 根据日历的规则，为给定的日历字段添加或减去指定的时间量
            cBegin.add(Calendar.DAY_OF_MONTH, 1);
            lDate.add(dateToLast(cBegin.getTime()));
        }
        return lDate;
    }

    public static List<DateVO> findEveryDays(Date dBegin, Date dEnd) {
        List<DateVO> params = new ArrayList<>(Constant.INITIAL_CAPACITY);
        Calendar calBegin = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calBegin.setTime(dBegin);
        Calendar calEnd = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calEnd.setTime(dEnd);
        calEnd.add(Calendar.DAY_OF_MONTH, -2);
        // 判断两个时间是否为同一天
        if (!DateUtil.isSameDay(dBegin, dEnd)) {
            DateVO first = new DateVO();
            first.setStartTime(dBegin);
            first.setEndTime(dateToLast(dBegin));
            params.add(first);
        }
        // 测试此日期是否在指定日期之后
        while (calEnd.getTime().after(calBegin.getTime())) {
            DateVO res = new DateVO();
            // 根据日历的规则，为给定的日历字段添加或减去指定的时间量
            calBegin.add(Calendar.DAY_OF_MONTH, 1);
            res.setEndTime(dateToLast(calBegin.getTime()));
            res.setStartTime(dateToFast(calBegin.getTime()));
            params.add(res);
        }
        DateVO last = new DateVO();
        last.setStartTime(dateToFast(dEnd));
        last.setEndTime(dEnd);
        params.add(last);
        return params;
    }

    public static Date dateToFast(Date date) {
        return dateToFastOrLast(date, 1);
    }

    public static Date dateToLast(Date date) {
        return dateToFastOrLast(date, 2);
    }

    /**
     * 获取传入时间的前一天的初始和结束时间
     */
    public static Date getBeforeDate(Date date) {
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        instance.add(Calendar.DATE, -1);
        return instance.getTime();
    }

    /**
     * 获取传入时间的前n年时间点
     * @param n 例如: n = -1 表示当前时间的前一年， n = 1 表示获取后一年
     */
    public static Date getBeforeYear(Date date, int n) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.YEAR, n);
        return calendar.getTime();
    }

    /**
     * 获取传入时间的前n月时间点
     * @param n 例如: n = -1 表示当前时间的前一月， n = 1 表示获取后一月
     */
    public static Date getBeforeOrNextNumMonth(Date date, int n) {
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        instance.add(Calendar.MONTH, n);
        return instance.getTime();
    }

    /**
     * 获取传入时间的前n天时间点
     * @param n 例如: n = -1 表示当前时间的前一天， n = 1 表示获取后一天
     */
    public static Date getBeforeDay(Date date, int n) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, n);
        return calendar.getTime();
    }

    public static String dateToString(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }

    /**
     *
     * @param date 2020-06-12 15:00:00
     * @param type 1 date 的开始时间例如： 2020-06-12 00:00:00
     *             2 date 的结束时间例如： 2020-06-12 23:59:59
     * @return
     */
    public static Date dateToFastOrLast(Date date, Integer type) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int y = calendar.get(Calendar.YEAR);
        int m = calendar.get(Calendar.MONTH) + 1;
        int day = calendar.get(Calendar.DAY_OF_MONTH);
        String dateStr;
        if (Objects.equals(1, type)) {
            dateStr = y + "-" + m + "-" + day + " 00:00:00";
        } else {
            dateStr = y + "-" + m + "-" + day + " 23:59:59";
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            Date parse = sdf.parse(dateStr);
            calendar.setTime(parse);
        } catch (ParseException e) {
            LOGGER.info("解析异常:", e);
        }
        return calendar.getTime();
    }

    public static List<DateVO> getMonthBetweenStartTimeAndEndTime(Date startTime, Date endTime) {
        List<DateVO> monthBetween = getMonthBetween(startTime, endTime);
        if (monthBetween.isEmpty()) {
            DateVO param = new DateVO();
            param.setStartTime(startTime);
            param.setEndTime(endTime);
            monthBetween.add(param);
            return monthBetween;
        }
        if (1 == monthBetween.size()) {
            DateVO param = monthBetween.get(0);
            param.setEndTime(endTime);
            monthBetween.set(0, param);
            return monthBetween;
        }
        DateVO param = monthBetween.get(0);
        param.setStartTime(startTime);
        DateVO last = monthBetween.get(monthBetween.size() - 1);
        last.setEndTime(endTime);
        monthBetween.set(0, param);
        monthBetween.set(monthBetween.size() - 1, last);
        return monthBetween;
    }

    public static List<DateVO> getMonthBetween(Date minDate, Date maxDate) {
        List<DateVO> res = new ArrayList<>(1);
        Calendar min = Calendar.getInstance();
        Calendar max = Calendar.getInstance();

        min.setTime(minDate);
        min.set(min.get(Calendar.YEAR), min.get(Calendar.MONTH), 1);

        max.setTime(maxDate);
        max.set(max.get(Calendar.YEAR), max.get(Calendar.MONTH), 2);

        while (min.before(max)) {
            DateVO param = new DateVO();
            Date time = min.getTime();
            param.setStartTime(getMonthFirstOrLastDay(time, 0));
            param.setEndTime(getMonthFirstOrLastDay(time, 1));
            res.add(param);
            min.add(Calendar.MONTH, 1);
        }
        return res;
    }

    public static int countMonthNumBetweenDate(Date startTime, Date endTime) {
        Calendar min = Calendar.getInstance();
        min.setTime(startTime);
        Calendar max = Calendar.getInstance();
        max.setTime(endTime);
        int year = max.get(Calendar.YEAR) - min.get(Calendar.YEAR);
        //开始日期若小月结束日期
        if (0 > year) {
            year = -year;
            return year * MONTHS + min.get(Calendar.MONTH) - max.get(Calendar.MONTH);
        }
        return year * MONTHS + max.get(Calendar.MONTH) - min.get(Calendar.MONTH);
    }

    /**
     * @param date 传入的时间点  2020-03-12 15:30:00
     * @param type 0 获取传入时间的月份开始时间 2020-03-01 00:00:00
     *             1 获取传入时间的月份最后一天的时刻 2020-03-31 23:59:59
     * @return date
     */
    public static Date getMonthFirstOrLastDay(Date date, Integer type) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        if (Objects.equals(0, type)) {
            // 获取传入时间的月份的第一天 yyyy-MM-dd 00:00:00
            calendar.add(Calendar.MONTH, 0);
            calendar.set(Calendar.DAY_OF_MONTH, 1);
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
        } else {
            // 获取传入时间的月份的最后一天 yyyy-MM-dd 23:59:59
            calendar.add(Calendar.MONTH, 1);
            calendar.set(Calendar.DAY_OF_MONTH, 0);
            calendar.set(Calendar.HOUR_OF_DAY, LAST_HOUR);
            calendar.set(Calendar.MINUTE, LAST_MIN);
            calendar.set(Calendar.SECOND, LAST_MIN);
        }
        return calendar.getTime();
    }


    /**
     * 时间转换成iso格式
     * @param date
     * @return
     */
    public static Date dateToIsoDate(Date date) {
        //T代表后面跟着时间，Z代表UTC统一时间
        SimpleDateFormat format =
                new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        format.setCalendar(new GregorianCalendar(new SimpleTimeZone(0, "GMT")));
        String isoDate = format.format(date);
        try {
            return format.parse(isoDate);
        } catch (ParseException e) {
            LOGGER.info("转换错误", e);
        }
        return null;
    }

    /**
     * 获取本周开始时间
     */
    public static Date getCurrentWeekStartTimes(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
        cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        return cal.getTime();
    }

    /**
     * 获取本周结束时间
     */
    public static Date getCurrentWeekEndTimes(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getCurrentWeekStartTimes(date));
        cal.add(Calendar.DAY_OF_WEEK, 6);
        cal.set(Calendar.HOUR_OF_DAY, LAST_HOUR);
        cal.set(Calendar.MINUTE, LAST_MIN);
        cal.set(Calendar.SECOND, LAST_MIN);
        cal.set(Calendar.MILLISECOND, MAX_MILLISECOND);
        return cal.getTime();
    }

    /**
     * 获取当年的开始时间戳
     *
     * @return
     */
    public static Date getCurrentYearStartTime(Date date) {
        // 获取当前日期
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(date.getTime());
        calendar.add(Calendar.YEAR, 0);
        calendar.add(Calendar.MONTH, 0);
        calendar.set(Calendar.DAY_OF_YEAR, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * 获取当年的最后时间戳
     *
     * @return
     */
    public static Date getCurrentYearEndTime(Date date) {
        // 获取当前日期
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(date.getTime());
        int year = calendar.get(Calendar.YEAR);
        calendar.clear();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.HOUR_OF_DAY, LAST_HOUR);
        calendar.set(Calendar.MINUTE, LAST_MIN);
        calendar.set(Calendar.SECOND, LAST_MIN);
        calendar.set(Calendar.MILLISECOND, MAX_MILLISECOND);
        calendar.roll(Calendar.DAY_OF_YEAR, -1);
        return calendar.getTime();
    }
}
