package com.testor.common.util;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.poi.ss.formula.functions.Now;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class DateUtil {

    public static final String[] YEAR_MONTHS = new String[]{"01", "02", "03",
            "04", "05", "06", "07", "08", "09", "10", "11", "12"};

    public static final String[] CHINA_MONTHS = new String[]{"一月", "二月",
            "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"};

    public static final String[] DAY_HOURS = new String[]{"00", "01", "02",
            "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13",
            "14", "15", "16", "17", "18", "19", "20", "21", "22", "23"};

    public static final String[] MONTH_DAYS = new String[]{"01", "02", "03",
            "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14",
            "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25",
            "26", "27", "28", "29", "30", "31"};

    /**
     * 生成多层日期目录
     *
     * @param level 目录层数(最多3层)即:月(200906)-日(0605)-时(01)
     * @return
     */
    public static String generateDateDir(int level) {
        if (level < 1 || level > 5) {
            level = 3;// 默认3
        }
        SimpleDateFormat levelOne = new SimpleDateFormat("yyyyMM");
        SimpleDateFormat levelTwo = new SimpleDateFormat("MMdd");
        SimpleDateFormat levelThree = new SimpleDateFormat("HH");
        SimpleDateFormat levelFour = new SimpleDateFormat("yyyy-MM-dd");

        String s = "/";
        String destDirectory = "";
        Date date = new Date(System.currentTimeMillis());

        switch (level) {
            case 1:
                destDirectory += levelOne.format(date);
                break;
            case 2:
                destDirectory += levelOne.format(date) + s + levelTwo.format(date);
                break;
            case 3:
                destDirectory += levelOne.format(date) + s + levelTwo.format(date)
                        + s + levelThree.format(date);
                break;
            case 4:
                destDirectory = levelFour.format(date);
                break;
            case 5:
                destDirectory = levelFour.format(getYesterday());
                break;
        }
        return destDirectory;
    }


    /**
     * 判断两个 LocalDateTime 不在同一天 且 target 在 compare 之后
     * @param target
     * @param compare
     * @return
     */
    public static boolean notSameDayAndAfter(LocalDateTime target, LocalDateTime compare) {
        // 判断两个 LocalDateTime 不在同一天
        boolean isSameDay = !target.toLocalDate().isEqual(compare.toLocalDate());

        // 判断 target 是否在 compare 之后
        boolean isAfter = target.isAfter(compare);

        return isSameDay && isAfter;
    }

    /**
     * 获取年
     *
     * @param date
     * @return
     */
    public static int getYear(Date date) {
        return getValue(date, Calendar.YEAR);
    }

    /**
     * 获取月
     *
     * @param date
     * @return
     */
    public static int getMonth(Date date) {
        return getValue(date, Calendar.MONTH);
    }

    /**
     * 获取星期
     *
     * @param date
     * @return
     */
    public static int getWeek(Date date) {
        return getValue(date, Calendar.DAY_OF_WEEK);
    }

    /**
     * 获取日
     *
     * @param date
     * @return
     */
    public static int getDay(Date date) {
        return getValue(date, Calendar.DAY_OF_MONTH);
    }

    /**
     * 获取小时
     *
     * @param date
     * @return
     */
    public static int getHour(Date date) {
        return getValue(date, Calendar.HOUR_OF_DAY);
    }

    /**
     * 获取分钟
     *
     * @param date
     * @return
     */
    public static int getMinute(Date date) {
        return getValue(date, Calendar.MINUTE);
    }

    /**
     * 获取分钟
     *
     * @param date
     * @return
     */
    public static int getSecond(Date date) {
        return getValue(date, Calendar.SECOND);
    }

    /**
     * @param date
     * @param field
     * @return
     */
    private static int getValue(Date date, int field) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(date.getTime());
        return calendar.get(field);
    }

    /**
     * 解析日期
     *
     * @param strDate
     * @return
     * @throws ParseException
     */
    public static Date convertStrToDate(String strDate, String pattern) {
        if (StringUtils.isBlank(strDate) || StringUtils.isBlank(pattern)) {
            return null;
        }
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(pattern);
            return sdf.parse(strDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 字符串转calendar
     *
     * @param date    日期的字符串
     * @param pattern 日期的格式
     * @return
     */
    public static Calendar convertStrToCalendar(String date, String pattern) {
        Calendar calendar = null;
        try {
            calendar = Calendar.getInstance();
            SimpleDateFormat format = new SimpleDateFormat(pattern);
            calendar.setTime(format.parse(date));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return calendar;
    }

    /**
     * 格式化date为指定的格式字符串
     *
     * @param date
     * @param pattern
     * @return
     */
    public static String convertDateToStr(Date date, String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(date);
    }

    /**
     * 转换日期为字符串
     *
     * @param date
     * @return
     */
    public static String convertDateToYMDStr(Date date) {
        if (date == null) {
            return null;
        }
        return new SimpleDateFormat("yyyy-MM-dd").format(date);
    }

    public static String convertDateToYMDStrs(Date date) {
        if (date == null) {
            return null;
        }
        return new SimpleDateFormat("yyyy-MM").format(date);
    }

    /**
     * 给日期增加值
     *
     * @param date
     * @param field
     * @param amount
     * @return
     */
    public static Date add(Date date, int field, int amount) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(date.getTime());
        calendar.add(field, amount);
        return new Date(calendar.getTimeInMillis());
    }

    /**
     * 取上个月的第一天
     */
    public static Calendar getLastMonFirstDay(Calendar calendar) {
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH);
        if (month > 0) {
            month--;
        } else {
            year--;
            month = 11;
        }
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return calendar;
    }

    /**
     * 取上个月的最后一天
     */
    public static Calendar getLastMonLastDay(Calendar calendar) {
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        return calendar;
    }

    /**
     * 取得上一天
     */
    public static Calendar getLastDay(Calendar calendar) {
        calendar.add(Calendar.DAY_OF_YEAR, -1);
        return calendar;
    }

    /**
     * 取上个周的最后一天
     */
    public static Calendar getLastweekLastDay(Calendar calendar) {
        calendar.add(Calendar.SUNDAY, -7);
        return calendar;
    }

    /**
     * 取一天中最大时间 毫秒为999
     *
     * @param day
     * @return
     * @throws ParseException
     */
    public static Date getEndOfDay(Date day) {

        if (day == null) {
            day = new Date();
        }

        Calendar cal = Calendar.getInstance();
        cal.setTime(day);
        cal.set(Calendar.HOUR_OF_DAY, cal.getMaximum(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, cal.getMaximum(Calendar.MINUTE));
        cal.set(Calendar.SECOND, cal.getMaximum(Calendar.SECOND));
        cal.set(Calendar.MILLISECOND, cal.getMaximum(Calendar.MILLISECOND));

        return cal.getTime();
    }

    /**
     * 取一天中最大时间 毫秒为0
     *
     * @param day
     * @return
     * @throws ParseException
     */
    public static Date getEndZeroMillOfDay(Date day) {

        if (day == null) {
            day = new Date();
        }

        Calendar cal = Calendar.getInstance();
        cal.setTime(day);
        cal.set(Calendar.HOUR_OF_DAY, cal.getMaximum(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, cal.getMaximum(Calendar.MINUTE));
        cal.set(Calendar.SECOND, cal.getMaximum(Calendar.SECOND));
        cal.set(Calendar.MILLISECOND, 0);

        return cal.getTime();
    }

    /**
     * 取一天中最小时间
     *
     * @param day
     * @return
     * @throws ParseException
     */
    public static Date getStartOfDay(Date day) {

        if (day == null) {
            day = new Date();
        }

        Calendar cal = Calendar.getInstance();
        cal.setTime(day);
        cal.set(Calendar.HOUR_OF_DAY, cal.getMinimum(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, cal.getMinimum(Calendar.MINUTE));
        cal.set(Calendar.SECOND, cal.getMinimum(Calendar.SECOND));
        cal.set(Calendar.MILLISECOND, cal.getMinimum(Calendar.MILLISECOND));

        return cal.getTime();
    }

    /**
     * 取今天的最小时间
     *
     * @return
     * @throws ParseException
     */
    public static Date getTodayStart() {
        return getStartOfDay(new Date());
    }

    /**
     * 计算两个日期之间相差的天数
     *
     * @param startDate 较小的时间
     * @param endDate   较大的时间
     * @return 相差天数
     */
    public static int daysBetween(Date startDate, Date endDate) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(startDate);
        long time1 = cal.getTimeInMillis();
        cal.setTime(endDate);
        long time2 = cal.getTimeInMillis();
        long betweenDays = (time2 - time1) / (1000 * 3600 * 24);
        return Integer.parseInt(String.valueOf(betweenDays));
    }

    /**
     * 获取当前月份天数的数组
     *
     * @return
     */
    public static String[] getCurrentMonthDaysArray() {
        return getMonthDaysArray(new Date());
    }

    /**
     * 获取指定月份天数的数组
     *
     * @return
     */
    public static String[] getMonthDaysArray(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int maxDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        String[] array = new String[maxDay];
        System.arraycopy(MONTH_DAYS, 0, array, 0, maxDay);
        return array;
    }

    /**
     * 获取当前月的第一天
     *
     * @return
     */
    public static Date getCurrentFirstDayOfMonth() {
        return getFirstDayOfMonth(new Date());
    }

    /**
     * 获取当前月的
     *
     * @return
     */
    public static Date getCurrentLastDayOfMonth() {
        return getLastDayOfMonth(new Date());
    }

    /**
     * 获取指定时间中月的第一天
     *
     * @return
     */
    public static Date getFirstDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, 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 getLastDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH,
                calendar.getMaximum(Calendar.DAY_OF_MONTH));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar.getTime();
    }

    /**
     * 获取当前年的第一天
     *
     * @return
     */
    public static Date getCurrentFirstDayOfYear() {
        return getFirstDayOfYear(new Date());
    }

    /**
     * 获取指定年份的第一天
     *
     * @return
     */
    public static Date getFirstDayOfYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        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 getYesterday() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, -1);
        return cal.getTime();
    }

    public/**
     * 获取今天
     */
    static Date getToday() {
        Calendar cal = Calendar.getInstance();
        return cal.getTime();
    }

    /**
     * 获取前一天
     *
     * @return
     */
    public static Date getYesterday(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DATE, -1);
        return cal.getTime();
    }

    /**
     * 获取后一天
     *
     * @return
     */
    public static Date getTomorrow(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DATE, 1);
        return cal.getTime();
    }

    /**
     * 获取前一个月
     *
     * @return
     */
    public static Date getLastMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, -1);
        return cal.getTime();
    }

    /**
     * 获取后一个月
     *
     * @return
     */
    public static Date getNextMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, 1);
        return cal.getTime();
    }

    /**
     * 获取大写的月份
     *
     * @param date
     * @return
     */
    public static String getChinaMonth(Date date) {
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        return CHINA_MONTHS[instance.get(Calendar.MONTH)];
    }

    /**
     * 比较两个时间的时分
     *
     * @param date1
     * @param date2
     * @return
     */
    public static int compareToHourMin(Date date1, Date date2) {
        Calendar calendar1 = Calendar.getInstance();
        calendar1.setTime(date1);
        calendar1.set(Calendar.SECOND, 0);

        Calendar temp = Calendar.getInstance();
        temp.setTime(date2);

        Calendar calendar2 = (Calendar) calendar1.clone();
        calendar2.set(Calendar.HOUR_OF_DAY, temp.get(Calendar.HOUR_OF_DAY));
        calendar2.set(Calendar.MINUTE, temp.get(Calendar.MINUTE));
        calendar2.set(Calendar.SECOND, 0);

        return calendar1.compareTo(calendar2);
    }

    /**
     * 计算两个日期是否是一周(周一作为一周的开始时间)
     *
     * @param date1
     * @param date2
     * @return
     */
    public static boolean isSameWeek(Date date1, Date date2) {

        Calendar calendar1 = Calendar.getInstance();
        calendar1.setTime(date1);
        calendar1.setFirstDayOfWeek(Calendar.MONDAY);

        Calendar calendar2 = Calendar.getInstance();
        calendar2.setTime(date2);
        calendar2.setFirstDayOfWeek(Calendar.MONDAY);

        if (calendar1.get(Calendar.WEEK_OF_YEAR) == calendar2
                .get(Calendar.WEEK_OF_YEAR)) {
            return true;
        }

        return false;
    }

    /**
     * 根据开始时间和结束时间返回时间段内的时间集合
     *
     * @param startDate
     * @param endDate
     * @return List
     */
    public static List<Date> getDatesBetweenTwoDate(Date startDate, Date endDate) {
        List<Date> dates = new ArrayList<Date>();
        dates.add(startDate);// 把开始时间加入集合
        Calendar cal = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        cal.setTime(startDate);
        while (true) {
            cal.add(Calendar.DAY_OF_MONTH, 1);
            if (endDate.after(cal.getTime())
                    && !DateUtils.isSameDay(endDate, cal.getTime())) {
                dates.add(cal.getTime());
            } else {
                break;
            }
        }
        if (startDate.compareTo(endDate) != 0) {
            dates.add(endDate);// 把结束时间加入集合
        }
        return dates;
    }

    /**
     * 获取时间段内的时间字符串集合
     *
     * @param startDate
     * @param endDate
     * @param dateFormat
     * @return
     */
    public static List<String> getDateCollection(Date startDate, Date endDate,
                                                 String dateFormat) {

        if (dateFormat == null || StringUtils.equals(dateFormat, "")) {
            dateFormat = "yyyy-MM-dd";
        }
        List<String> dates = new ArrayList<String>();
        dates.add(DateUtil.convertDateToStr(startDate, dateFormat));
        Calendar cal = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        cal.setTime(startDate);
        while (true) {
            cal.add(Calendar.DAY_OF_MONTH, 1);
            if (endDate.after(cal.getTime())
                    && !DateUtils.isSameDay(endDate, cal.getTime())) {
                dates.add(DateUtil.convertDateToStr(cal.getTime(), dateFormat));
            } else {
                break;
            }
        }
        dates.add(DateUtil.convertDateToStr(endDate, dateFormat));// 把结束时间加入集合
        return dates;
    }

    /**
     * 获得某个月的日期表格
     *
     * @param month
     * @return List
     */
    public static List<Date> getDateTab(Date month) {
        Date startDate = getFirstDayOfMonth(month);
        Date endDate = getLastDayOfMonth(month);
        Calendar cal1 = Calendar.getInstance();
        Calendar cal2 = Calendar.getInstance();
        cal1.setTime(startDate);
        cal2.setTime(endDate);
        int i = cal1.get(Calendar.DAY_OF_WEEK);
        int j = cal2.get(Calendar.DAY_OF_WEEK);
        cal1.add(Calendar.DAY_OF_MONTH, -i + 1);
        cal2.add(Calendar.DAY_OF_MONTH, 7 - j);
        Date beforeDate = cal1.getTime();
        Date afterDate = cal2.getTime();
        return getDatesBetweenTwoDate(beforeDate, afterDate);
    }

    /**
     * 转化大写的月份（一月……十二月）为数字月份（01……12）
     *
     * @param chinaMonthName
     * @return
     */
    public static String convertMonthToNum(String chinaMonthName) {
        int i = ArrayUtils.indexOf(CHINA_MONTHS, chinaMonthName);
        return i > -1 ? YEAR_MONTHS[i] : "";
    }

    /**
     * 将两个时间根据指定天数分割为多个时间段
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @param fate      每个时间段间隔的天数
     * @return 分割后的时间段:[[开始时间,结束时间],[开始时间,结束时间],...]
     */
    public static List<Date[]> toTimeSlot(Date startDate, Date endDate,
                                          Integer fate) {
        if (startDate == null || endDate == null) {
            /* 开始时间或结束时间为空返回空集合 */
            return new ArrayList<Date[]>();
        }
        List<Date[]> result = new ArrayList<Date[]>();
        /* 间隔天 */
        List<Date> days = getDatesBetweenTwoDate(startDate, endDate);
        /* 总天数 */
        Integer dayNumber = days.size();
        if (dayNumber < fate) {
            /* 如果间隔天数大于总天数则直接返回开始时间和结束时间 */
            result.add(new Date[]{startDate, endDate});
        } else {
            /* 时间段个数 */
            Integer size = dayNumber / fate;
            /* 余数 */
            Integer remain = dayNumber % fate;
            if (remain > 0) {
                /* 余数大于零则将时间段个数加一 */
                size += 1;
            } else {
                /* 否则则将余数设置为间隔天数 */
                remain = fate;
            }
            /* 计算时间段 */
            for (int i = 1; i <= size; i++) {
                Integer start = i - 1;
                /* 时间段开始时间所在的索引 */
                Integer startIndex = start * fate;// +(start==0?0:1);
                /* 时间段结束时间所在的索引 */
                Integer endIndex = startIndex + fate;
                if (i == size) {
                    endIndex = startIndex + (remain - 1);
                }
                result.add(new Date[]{days.get(startIndex),
                        days.get(endIndex - (start == 0 ? 1 : 0)) // 如果当前是第一次遍历结束时间索引减一
                });
            }
        }
        return result;
    }

    /**
     * 获取指定时间的时间戳【毫秒】
     *
     * @param date
     * @return
     */
    public static Long getTime(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.getTimeInMillis();
    }

    /**
     * 根据字符串获取date
     */
    public static Date getTime(String date, String format) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(format);
        try {
            return dateFormat.parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String getTime(Date date, String format) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(format);
        return dateFormat.format(date);
    }

    /**
     * 计算两个时间相差时间，格式 *天*小时*分钟*秒
     */
    public static String 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 day + "天" + hour + "小时" + min + "分钟" + sec + "秒";
    }

    /**
     * 计算两个时间相差多少分钟
     */
    public static Long getDateDifferenceMinute(Date endDate, Date nowDate) {


        long nm = 1000 * 60;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少分钟
        long min = diff / nm;

        return min;
    }

    public static Date localDateTimeToDate(LocalDateTime localDateTime) {
        ZoneId zoneId = ZoneId.systemDefault(); // 获取系统默认时区
        // 转换为 Instant
        Instant instant = localDateTime.atZone(zoneId).toInstant();
        // 转换为 Date
        return Date.from(instant);
    }
    public static LocalDateTime dateToLocalDateTime(Date date) {
        return cn.hutool.core.date.DateUtil.toLocalDateTime(date);
    }

    public static String getTodayStartString() {
        return LocalDate.now()
                .atStartOfDay()
                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

    public static void main(String[] args) {
        LocalDateTime startDate = com.testor.common.util.DateUtil.dateToLocalDateTime( new Date());
        System.out.println(startDate);
    }

}
