package com.patzn.lims.common;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 日期工具类
 * </p>
 *
 * @author hubin
 * @since 2018-04-09
 */
public class DateUtils {

    /**
     * <p>
     * 字符串日期转为 Date 日期类型
     * </p>
     *
     * @param date 字符串日期
     * @return
     */
    public static Date toDate(String date) {
        try {
            return new DateTime(date).toDate();
        } catch (Exception e) {
            // to do nothing
        }
        return null;
    }


    public static String toYearMonthDay(Date date) {
        return DateUtils.dateTransfer(date, "yyyy-MM-dd");
    }

    public static String toYearMonthDayEasy(Date date) {
        return DateUtils.dateTransfer(date, "yyyyMMdd");
    }


    public static String toYearMonthDayTimeFormat(Date date) {
        return DateUtils.dateTransfer(date, "yyyy-MM-dd HH:mm");
    }


    public static boolean theTwoDateIsSameDay(Date date1, Date date2) {
        if (null == date1 || null == date2) {
            return false;
        }
        return DateUtils.toYearMonthDay(date1).equals(DateUtils.toYearMonthDay(date2));
    }


    public static String dateTransfer(Date date, String format) {
        if (null == date) {
            return "";
        }
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            return sdf.format(date);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }


    public static String toYearMonthHourMiniDay(Date date) {
        return DateUtils.dateTransfer(date, "yyyy-MM-dd HH:mm");
    }

    public static String toYearMonthDayChinese(Date date) {
        return DateUtils.dateTransfer(date, "yyyy年MM月dd日");
    }

    public static String toYearMonthDayChineseStr(String dateStr) {
        if ("".equals(dateStr)) {
            return "";
        }
        try {
            return dateStr.substring(0, 4) + "年" + dateStr.substring(5, 7) + "月" + dateStr.substring(8, 10) + "日";
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    public static String toYearMonthDayPoint(Date date) {
        return DateUtils.dateTransfer(date, "yyyy.MM.dd");
    }


    public static Date dateStringtoDate(String date) {
        if (StringUtils.isBlank(date)) {
            return null;
        }
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return sdf.parse(date);
        } catch (Exception e) {
            try {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                return sdf.parse(date);
            } catch (Exception ee) {
                ee.printStackTrace();
                return null;
            }
        }
    }

    public static Date dateStringtoDate(String date, String format) {
        if (StringUtils.isBlank(date)) {
            return null;
        }
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            return sdf.parse(date);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String getMinDate(List<String> dateList) {
        if (null == dateList || dateList.size() == 0) {
            return "";
        }
        List<String> dateArray = dateList.stream().filter(date -> !"".equals(date)).collect(Collectors.toList());
        if (dateArray.size() == 0) {
            return "";
        }
        Map<String, Integer> dateMap = DateUtils.getDateMap(dateArray);
        Set<String> keySet = dateMap.keySet();
        String[] sorttedArray = new String[keySet.size()];
        Iterator<String> iter = keySet.iterator();
        int index = 0;
        while (iter.hasNext()) {
            String key = iter.next();
            sorttedArray[index++] = key;
        }
        String timeString = sorttedArray[0];
        if (timeString.length() >= 10) {
            String trueSreString = timeString.substring(0, 10);
            return trueSreString;

        } else {
            return "";
        }
    }

    public static Date getMinDateByDateList(List<Date> dateList) {
        if (null == dateList || dateList.size() == 0) {
            return null;
        }
        List<Date> dateArray = dateList.stream().filter(date -> null != date).collect(Collectors.toList());
        if (dateArray.size() == 0) {
            return null;
        }
        Date minDate = dateArray.get(0);
        for (Date date : dateArray) {
            if (minDate.after(date)) {
                minDate = date;
            }
        }
        return minDate;
    }

    public static Date getMaxDateByDateList(List<Date> dateList) {
        if (CollectionUtils.isEmpty(dateList)) {
            return null;
        }
        List<Date> dateArray = dateList.stream().filter(date -> null != date).collect(Collectors.toList());
        if (dateArray.size() == 0) {
            return null;
        }
        Date maxDate = dateArray.get(0);
        for (Date date : dateArray) {
            if (date.after(maxDate)) {
                maxDate = date;
            }
        }
        return maxDate;
    }


    public static int getDurationDays(List<Date> dateList) {
        Date dateMin = DateUtils.getMinDateByDateList(dateList);
        Date dateMax = DateUtils.getMaxDateByDateList(dateList);
        return DateUtils.differentDays(dateMin, dateMax);
    }


    /**
     * date2比date1多的天数
     *
     * @param date1
     * @param date2
     * @return
     */
    public static int differentDays(Date date1, Date date2) {
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(date1);

        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(date2);
        int day1 = cal1.get(Calendar.DAY_OF_YEAR);
        int day2 = cal2.get(Calendar.DAY_OF_YEAR);

        int year1 = cal1.get(Calendar.YEAR);
        int year2 = cal2.get(Calendar.YEAR);
        if (year1 != year2)   //同一年
        {
            int timeDistance = 0;
            for (int i = year1; i < year2; i++) {
                if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0)    //闰年
                {
                    timeDistance += 366;
                } else    //不是闰年
                {
                    timeDistance += 365;
                }
            }

            return timeDistance + (day2 - day1);
        } else {
            //不同年
            return day2 - day1;
        }
    }


    public static Map<String, Integer> getDateMap(List<String> dateArray) {
        Map<String, Integer> dateMap = new TreeMap<>();
        int i, arrayLen;
        arrayLen = dateArray.size();
        for (i = 0; i < arrayLen; i++) {
            String dateKey = dateArray.get(i);
            if (dateMap.containsKey(dateKey)) {
                int value = dateMap.get(dateKey) + 1;
                dateMap.put(dateKey, value);
            } else {
                dateMap.put(dateKey, 1);
            }
        }
        return dateMap;
    }

    public static String getMaxDate(List<String> dateList) {
        if (dateList.size() == 0 || null == dateList) {
            return "";
        }
        List<String> dateArray = dateList.stream().filter(date -> !"".equals(date)).collect(Collectors.toList());
        if (null == dateArray || dateArray.size() == 0) {
            return "";
        }
        Map<String, Integer> dateMap = DateUtils.getDateMap(dateArray);
        Set<String> keySet = dateMap.keySet();
        String[] sorttedArray = new String[keySet.size()];
        Iterator<String> iter = keySet.iterator();
        int index = 0;
        while (iter.hasNext()) {
            String key = iter.next();
            sorttedArray[index++] = key;
        }
        int sorttedArrayLen = sorttedArray.length;
        String timeString = sorttedArray[sorttedArrayLen - 1];
        if (timeString.length() >= 16) {
            String trueSreString = timeString.substring(0, 16);
            return trueSreString;
        } else {
            return timeString;
        }
    }


    public static String getMinToMax(List<String> dateList) {
        String minDate = DateUtils.getMinDate(dateList);
        String maxDate = DateUtils.getMaxDate(dateList);
        if (!minDate.equals(maxDate)) {
            return minDate + "～" + maxDate;
        }
        if (!"".equals(minDate)) {
            return minDate;
        }
        return "";
    }


    public static long getDaysBetweenTwoDate(Date datePre, Date dateNext) {
        if (null == dateNext || null == datePre) {
            return 0;
        }
        return (dateNext.getTime() - datePre.getTime()) / (24 * 60 * 60 * 1000);
    }


    public static long getDaysInListLong(List<Long> dateLongList) {
        if (CollectionUtils.isEmpty(dateLongList)) {
            return 0;
        }
        if (dateLongList.size() < 2) {
            return 0;
        }
        return (dateLongList.get(dateLongList.size() - 1) - dateLongList.get(0)) / (24 * 60 * 60 * 1000);
    }

    public static Date getMinDateInDateLongList(List<Long> dateLongList) {
        if (CollectionUtils.isEmpty(dateLongList)) {
            return null;
        }
        return new Date(dateLongList.get(0));
    }

    public static boolean isOverlap(Date leftStartDate, Date leftEndDate, Date rightStartDate, Date rightEndDate) {
        return
                ((leftStartDate.getTime() >= rightStartDate.getTime())
                        && leftStartDate.getTime() < rightEndDate.getTime())
                        ||
                        ((leftStartDate.getTime() > rightStartDate.getTime())
                                && leftStartDate.getTime() <= rightEndDate.getTime())
                        ||
                        ((rightStartDate.getTime() >= leftStartDate.getTime())
                                && rightStartDate.getTime() < leftEndDate.getTime())
                        ||
                        ((rightStartDate.getTime() > leftStartDate.getTime())
                                && rightStartDate.getTime() <= leftEndDate.getTime());

    }

    /**
     * 判定是否日期格式
     *
     * @param str
     * @param format
     * @return
     */
    public static boolean isValidDate(String str, String format) {
        if (StringUtils.isBlank(format)) {
            return false;
        }
        if (Objects.equals(CommonConstants.YEAR_MONTH_DAY.toUpperCase(), format.toUpperCase()) ) {
            // 如果格式不是 yyyy-MM-dd, 则不需要验证此处
            return false;
        }
        boolean convertSuccess = true;
        // 指定日期格式为四位年/两位月份/两位日期，注意yyyy-MM-dd区分大小写；
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        try {
            // 设置lenient为false.
            // 否则SimpleDateFormat会比较宽松地验证日期，比如2007-02-29会被接受，并转换成2007-03-01
            sdf.setLenient(false);
            sdf.parse(str);
        } catch (ParseException e) {
            // e.printStackTrace();
            // 如果throw java.text.ParseException或者NullPointerException，就说明格式不对
            convertSuccess = false;
        }
        return convertSuccess;
    }

    /**
     * <p>
     * 把日期格式根据条件转换为时分秒为每天的开始还是结束的日期
     * </p>
     *
     * @param date
     * @param begin 时分秒是 00:00:00 还是 23:59:59
     * @return
     */
    public static Date parseDate(Date date, boolean begin) {
        if (null == date) {
            return null;
        }
        if (begin) {
            date.setHours(0);
            date.setMinutes(0);
            date.setSeconds(0);
        } else {
            date.setHours(23);
            date.setMinutes(59);
            date.setSeconds(59);
        }
        return date;
    }



    public static Date dateAddDays(String date, Integer days) {
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            Calendar c = Calendar.getInstance();
            c.setTime(sf.parse(date));
            c.add(Calendar.DAY_OF_MONTH, days);
            return c.getTime();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public static Date dateAddDays(Date date, Integer days) {
        try {
            Calendar c = Calendar.getInstance();
            c.setTime(date);
            c.add(Calendar.DAY_OF_MONTH, days);
            return c.getTime();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public static Integer getHours(Date date) {
        Calendar calendar = Calendar.getInstance();//日历对象
        calendar.setTime(date);//设置当前日期
        return calendar.get(Calendar.HOUR_OF_DAY);
    }

    public static Date plusDay(int num, String newDate) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date currdate = format.parse(newDate);
        Calendar ca = Calendar.getInstance();
        ca.add(Calendar.DATE, num);// num为增加的天数，可以改变的
        currdate = ca.getTime();
        String enddate = format.format(currdate);
        return toDate(enddate);
    }

    public static boolean dateBetween(Date date, Date begin, Date end) {
        if (null == date || null == begin || null == end) {
            return false;
        } else {
            return date.after(begin) && date.before(end);
        }
    }

    /**
     * <p>
     * 获取集合中的连续的日期放到map中，假如集合中有2019-07-01、2019-07-02、2019-07-04、2019-07-05、2019-07-06、2019-07-08
     * 那么map中会有三个元素
     * ①key：2019-07-01，value：2019-07-02
     * ②key：2019-07-04，value：2019-07-06
     * ③key：2019-07-08，value：2019-07-08
     * 只比较到天，时分秒不比较
     * </p>
     *
     * @param dates
     * @return Map
     */
    public static Map<Date, Date> getContinuityDates(Collection<Date> dates) {
        if (CollectionUtils.isEmpty(dates)) {
            // 空的直接返回null
            return null;
        }
        // 放进一个有序的集合中
        List<Date> dateList = new ArrayList<>(dates);
        // 然后给这个List排序
        Collections.sort(dateList);
        List<Date> newList = new ArrayList<>();
        int newIndex = -1;
        for (int i = 0; i < dateList.size(); i++) {
            // 原来的list中的元素
            Date nowDate = dateList.get(i);
            if (newIndex == -1) {
                newList.add(nowDate);
                newIndex++;
                continue;
            }
            // 新的list中的元素
            Date newNowDate = newList.get(newIndex);
            if (!(CalendarUtils.sub(newNowDate, nowDate) == 0)) {
                // 如果不是同一天，加进去
                newList.add(nowDate);
                newIndex++;
            }
        }
        if (newList.size() == 1) {
            Map<Date, Date> map = new HashMap<>(1);
            map.put(dateList.get(0), dateList.get(0));
            return map;
        }
        // 先拿到第一个日期
        Date keyDate = newList.get(0);
        // 返回的 map
        Map<Date, Date> map = new LinkedHashMap<>(16);
        Date tmp;
        for (int i = 1; i < newList.size(); i++) {
            tmp = newList.get(i - 1);
            if (CalendarUtils.sub(tmp, newList.get(i)) > 1) {
                map.put(keyDate, tmp);
                keyDate = newList.get(i);
            }
            if (i == newList.size() - 1) {
                // 最后一个直接放进去
                map.put(keyDate, newList.get(i));
            }
        }
        return map;
    }

}
