package com.ssyf.common.core.util;

import cn.hutool.core.util.StrUtil;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

/**
 * 日期工具，提供对日期的相关操作，如：日期格式化，年月日时分秒的增减操作等
 *
 * @author: huwei
 * @date: 2020/1/2 13:53
 * @version: 1.0.0
 */
public class DateUtil {

    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";

    public static final String DATE_TIME_FORMAT_FOR_CHAIN = "yyyy年MM月dd日 HH时mm分ss秒";

    public static final String DATE_FORMAT_FOR_CHAIN = "yyyy年MM月dd日";

    public static String DATE_HOUR_PATTERN = "yyyy-MM-dd HH";

    public static final String DEFAULT_DATE_FORMAT2 = "yyyy-MM-dd";
    public static String DATE_MONTH_PATTERN = "yyyy-MM";

    public static Date now() {
        return new Date();
    }

    public static Date date1970() {
        return new Date(0);
    }

    public static Date incrementYear(Date date, int years) {
        return increment(date, years, Calendar.YEAR);
    }

    public static Date decrementYear(Date date, int years) {
        return decrement(date, years, Calendar.YEAR);
    }

    public static Date incrementMonth(Date date, int months) {
        return increment(date, months, Calendar.MONTH);
    }

    public static Date decrementMonth(Date date, int months) {
        return decrement(date, months, Calendar.MONTH);
    }

    public static Date incrementDay(Date date, int days) {
        return increment(date, days, Calendar.DATE);
    }

    public static Date decrementDay(Date date, int days) {
        return decrement(date, days, Calendar.DATE);
    }

    public static Date incrementHour(Date date, int hours) {
        return increment(date, hours, Calendar.HOUR_OF_DAY);
    }

    public static Date decrementHour(Date date, int hours) {
        return decrement(date, hours, Calendar.HOUR_OF_DAY);
    }

    public static Date incrementMinute(Date date, int minutes) {
        return increment(date, minutes, Calendar.MINUTE);
    }

    public static Date decrementMinute(Date date, int minutes) {
        return decrement(date, minutes, Calendar.MINUTE);
    }

    public static Date incrementSecond(Date date, int seconds) {
        return increment(date, seconds, Calendar.SECOND);
    }

    public static Date decrementSecond(Date date, int seconds) {
        return decrement(date, seconds, Calendar.SECOND);
    }

    public static Date incrementMills(Date date, int mills) {
        return increment(date, mills, Calendar.MILLISECOND);
    }

    public static Date decrementMills(Date date, int mills) {
        return decrement(date, mills, Calendar.MILLISECOND);
    }

    public static Calendar toCalendar(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar;
    }

    public static Date transferDate(LocalDateTime localDateTime){
        // 将此日期时间与时区相结合以创建 ZonedDateTime
        ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());
        // 本地时间线LocalDateTime到即时时间线Instant时间戳
        Instant instant = zonedDateTime.toInstant();
        // UTC时间(世界协调时间,UTC + 00:00)转北京(北京,UTC + 8:00)时间
        Date date = Date.from(instant);
        return date;
    }

    public static Date transferDate(LocalDate localDate){
        return transferDate(localDate.atStartOfDay());
    }

    public static String formatNow(){
        return format(new Date());
    }

    public static String format(Date date) {
        return format(date, DEFAULT_DATE_FORMAT);
    }

    public static String format(LocalDateTime localDateTime) {
        return format(localDateTime, DEFAULT_DATE_FORMAT);
    }

    public static String format(LocalDateTime localDateTime, String format) {
        return format(transferDate(localDateTime), format);
    }

    public static String format(LocalDate localDate) {
        return format(localDate, DEFAULT_DATE_FORMAT2);
    }

    public static String format(LocalDate localDate, String format) {
        return format(transferDate(localDate), format);
    }

    public static String formatDate() {
        return formatDate(new Date());
    }

    public static String formatDate(Date date) {
        return format(date, "yyyy-MM-dd");
    }

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

    public static Date parse(String dateString) {
        return parse(dateString, DEFAULT_DATE_FORMAT);
    }

    public static Date parse(String dateString, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        try {
            return sdf.parse(dateString);
        } catch (Exception e) {
            throw new RuntimeException("parse date exception ,data :" + dateString + " ,format :" + format);
        }
    }

    public static Date parse(String dateString, Date defaultValue) {
        return parse(dateString, DEFAULT_DATE_FORMAT, defaultValue);
    }

    public static Date parse(String dateString, String format, Date defaultValue) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        try {
            return sdf.parse(dateString);
        } catch (Exception e) {
        }
        return defaultValue;
    }

    public static Date parseDefaultNull(String dateString) {
        return parse(dateString, DEFAULT_DATE_FORMAT, null);
    }

    public static int getYear(Date date) {
        return getTime(date, Calendar.YEAR);
    }

    /**
     * 月份从0开始，所以
     *
     * @param date
     * @return
     */
    public static int getMonthFromZero(Date date) {
        return getTime(date, Calendar.MONTH);
    }

    public static int getMonthFromOne(Date date) {
        return getTime(date, Calendar.MONTH) + 1;
    }

    public static int getDayTime(Date date) {
        return getTime(date, Calendar.DATE);
    }

    public static int getHourTime(Date date) {
        return getTime(date, Calendar.HOUR_OF_DAY);
    }

    public static int getMinutes(Date date) {
        return getTime(date, Calendar.MINUTE);
    }

    public static int getSecond(Date date) {
        return getTime(date, Calendar.SECOND);
    }

    public static int getMillisecond(Date date) {
        return getTime(date, Calendar.MILLISECOND);
    }

    /**
     * 获取指定日期最后一天；即一月的天数
     *
     * @param date
     * @return
     */
    public static int getMonthLastDay(Date date) {
        Calendar a = toCalendar(date);
        a.set(Calendar.DATE, 1);
        a.roll(Calendar.DATE, -1);
        return a.get(Calendar.DATE);
    }

    public static int getTime(Date date, int dateType) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(dateType);
    }

    static private Date increment(Date date, int incrementNumber, int dateType) {
        Calendar calendar = toCalendar(date);
        calendar.set(dateType, getTime(date, dateType) + incrementNumber);
        return calendar.getTime();
    }

    static private Date decrement(Date date, int decrementNumber, int dateType) {
        Calendar calendar = toCalendar(date);
        calendar.set(dateType, getTime(date, dateType) - decrementNumber);
        return calendar.getTime();
    }

    /**
     * 今天 最后结束时间
     *
     * @return 今天日期最后时间 23:59:59
     */
    public static Date getTodayEndTime() {
        return getDateEndTime(new Date());
    }

    /**
     * 指定 最后结束时间
     *
     * @return 指定时间 最后时间 23:59:59
     */
    public static Date getDateEndTime(Date date) {
        String dateString = format(date, "yyyy-MM-dd 24:00:00");
        return parse(dateString, "yyyy-MM-dd hh:mm:ss");
    }

    public static Date getTodayStartTime() {
        return getDateStartTime(new Date());
    }

    public static Date getDateStartTime(Date date) {
        String dateString = format(date, "yyyy-MM-dd 00:00:00");
        return parse(dateString, "yyyy-MM-dd hh:mm:ss");
    }


    /**
     * @param endDate 结束时间
     * @param nowDate 当前时间
     * @return 相差分钟数
     */
    public static Long getBetweenMin(Date endDate, Date nowDate) {
        long minTime = 60 * 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少分钟
        long min = diff / minTime;
        return min;
    }

    /**
     * 通过时间秒毫秒数判断两个时间的间隔
     *
     * @param date1
     * @param date2
     * @return
     */
    public static int getBetweenDay(Date date1, Date date2) {
        int days = (int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24));
        return days;
    }

    /**
     * 计算两个日期之间相差的天数
     *
     * @param beginDate 较小的时间
     * @param endDate   较大的时间
     * @return 相差天数
     */

    public static int getTimeDistance(Date beginDate, Date endDate) {
        Calendar beginCalendar = Calendar.getInstance();
        beginCalendar.setTime(beginDate);
        Calendar endCalendar = Calendar.getInstance();
        endCalendar.setTime(endDate);
        long beginTime = beginCalendar.getTime().getTime();
        long endTime = endCalendar.getTime().getTime();
        //先算出两时间的毫秒数之差大于一天的天数
        int betweenDays = (int) ((endTime - beginTime) / (1000 * 60 * 60 * 24));
        //使endCalendar减去这些天数，将问题转换为两时间的毫秒数之差不足一天的情况
        endCalendar.add(Calendar.DAY_OF_MONTH, -betweenDays);
        //再使endCalendar减去1天
        endCalendar.add(Calendar.DAY_OF_MONTH, -1);
        //比较两日期的DAY_OF_MONTH是否相等
        if ((beginCalendar.get(Calendar.DAY_OF_MONTH) == endCalendar.get(Calendar.DAY_OF_MONTH))) {
            //相等说明确实跨天了
            return betweenDays + 1;
        } else {
            //不相等说明确实未跨天
            return betweenDays + 0;
        }
    }

    /**
     * 获取下个月的今天
     *
     * @param currDate
     * @return
     */
    public static Date getNextMonthToDay(Date currDate) {
        Calendar c = Calendar.getInstance();
        c.setTime(currDate);
        c.add(Calendar.MONTH, 1);
        return c.getTime();
    }

    /*
     * 字符串转localdateTime
     * */
    public static LocalDateTime stringToLocalDateTime(String date) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime localTime = LocalDateTime.parse(date, df);
        return localTime;
    }

    /*
     * 字符串转localdate
     * */
    public static LocalDate stringToLocalDate(String date) {
        if (StrUtil.isEmpty(date)){
            return null;
        }else {
            DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            LocalDate localDate = LocalDate.parse(date, df);
            return localDate;
        }

    }

    /*
     * LocalDateTime->字符串
     * */
    public static String localDateTimeToString(LocalDateTime localDateTime) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String format = localDateTime.format(df);
        return format;
    }

    /*
     * localdate->字符串
     * */
    public static String localDateToString(LocalDate localDate) {
        if (null != localDate) {
            DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            String format = localDate.format(df);
            return format;
        } else {
            return "";
        }

    }

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

    public static Date stringToDate(String date) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date birthDate = null;
        try {
            birthDate = dateFormat.parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return birthDate;
    }

    /*
     *LocalDate获取指定时间的后一天(字符串)
     * */
    public static String getTomorrow(LocalDate time) {
        ZonedDateTime zonedDateTime = time.atStartOfDay(ZoneId.systemDefault());
        Instant instant1 = zonedDateTime.toInstant();
        Date date = Date.from(instant1);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        return simpleDateFormat.format(calendar.getTime());
    }

    //获取当年的年份
    public static Integer getCurrentYear() {
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        return Integer.valueOf(year);
    }

    //获取某一年的开始日期
    public static Date getYearFirst(Integer year) {
        Calendar calendar = Calendar.getInstance();

        calendar.clear();

        calendar.set(Calendar.YEAR, year);

        Date currYearFirst = calendar.getTime();

        return currYearFirst;
    }

    //获取某年的最后一天日期
    public static Date getYearLast(Integer year) {
        Calendar calendar = Calendar.getInstance();

        calendar.clear();

        calendar.set(Calendar.YEAR, year);

        calendar.roll(Calendar.DAY_OF_YEAR, -1);

        Date currYearLast = calendar.getTime();

        return currYearLast;
    }

    //获取当前月的第一天日期
    public static String getMonthStart() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.add(Calendar.MONTH, -1);
        calendar.set(Calendar.DAY_OF_MONTH, 0);
        // 获取当月第一天和最后一天
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        String firstday;
        Calendar cale = Calendar.getInstance();

        cale = Calendar.getInstance();
        cale.add(Calendar.MONTH, 0);
        cale.set(Calendar.DAY_OF_MONTH, 1);
        firstday = format.format(cale.getTime());

        return firstday;
    }

    //获取当前月最后一天的日期
    public static String getMonthEnd() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.add(Calendar.MONTH, -1);
        calendar.set(Calendar.DAY_OF_MONTH, 0);
        // 获取当月第一天和最后一天
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        String lastday;
        Calendar cale = Calendar.getInstance();

        cale = Calendar.getInstance();
        cale.add(Calendar.MONTH, 1);
        cale.set(Calendar.DAY_OF_MONTH, 0);
        lastday = format.format(cale.getTime());

        return lastday;
    }

    public static String getHourStart() {
        String formatDate = format(new Date(), DATE_HOUR_PATTERN) + ":00:00";
        return formatDate;
    }

    public static String getHourEnd() {
        String formatDate = format(new Date(), DATE_HOUR_PATTERN) + ":59:59";
        return formatDate;
    }

    public static LocalDateTime millisecondToLocalDaTeTime(Long value) {
        long milliSecond = value;
        Date date = new Date();
        date.setTime(milliSecond);
        String format = new SimpleDateFormat("yyyy-MM-dd HH:ss:mm").format(date);
        LocalDateTime localDateTime = stringToLocalDateTime(format);
        return localDateTime;
    }

    //获取指定月份的一号
    public static String getAssignStartTime(LocalDateTime localDateTime, Integer value) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDateTime plus = localDateTime.plusMonths(value);

        LocalDateTime startDateTime = plus.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
        return startDateTime.format(fmt);
    }

    //获取指定月份的最后一天
    public static String getAssignEndTime(LocalDateTime localDateTime, Integer value) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDateTime plus = localDateTime.plusMonths(value);

        LocalDateTime endDateTime = plus.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX);
        return endDateTime.format(fmt);
    }

    //localdatetime转date
    public static Date localDateTimeToDate(LocalDateTime localDateTime) {
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = localDateTime.atZone(zoneId);
        return Date.from(zdt.toInstant());
    }


    public static LocalDate timezoneJson(String oldDateStr){
        Date date = null;
        Date date1 = null;
        String dateStr = null;
        try {
            dateStr = oldDateStr.replace("Z", " UTC");//是空格+UTC
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS Z");
            date1 = df.parse(dateStr);
            SimpleDateFormat df1 = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy", Locale.UK);
            date = df1.parse(date1.toString());

            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            String format = simpleDateFormat.format(date);

            return DateUtil.stringToLocalDate(format);

        } catch (ParseException e) {
            e.printStackTrace();
            return null;
        }
    }


    public static boolean after(LocalDate date1, LocalDate date2){


        return date1.isBefore(date2);
    }

    /**
     * 日期计算
     * @param date
     * @param num
     * @param type
     * @return
     */
    public static String dateAdd(Date date, long num, String type){
        Calendar afterNow = Calendar.getInstance();
        afterNow.setTime(date);
        switch (type){
            case "year":
                afterNow.add(Calendar.YEAR, (int) num);
                break;
            case  "month":
                afterNow.add(Calendar.MONTH, (int) num);
                break;
            case  "day":
                afterNow.add(Calendar.DAY_OF_YEAR, (int) num);
                break;
            case  "minute":
                afterNow.add(Calendar.MINUTE, (int) num);
                break;
            case  "sencond":
                afterNow.add(Calendar.SECOND, (int) num);
                break;
            default: break;
        }
        Date afterDate = afterNow.getTime();
        String afterDateStr =format(afterDate);
        return afterDateStr;
    }

    /**
     * 获取当前日期 date类型   yyyy-MM-dd
     * @return
     */
    public static Date parseDate() {
        String date=format(new Date());
        return parse(date, DEFAULT_DATE_FORMAT2);
    }

    /**
     * 比较两个日期之间的大小
     * @param date1
     * @param date2
     * @return true:date1>date2  false:date1<date2
     */
    public static boolean parseDate(String date1, String date2) {
        Date d1=parse(date1,DEFAULT_DATE_FORMAT2);
        Date d2=parse(date2,DEFAULT_DATE_FORMAT2);
        long long1 =d1.getTime();
        long long2= d2.getTime();
        if(long1 > long2){
            return true;
        }
        return false;

    }
    /**
     * 获取当月
     * @return
     */
    public static String getMonthNow(){
        SimpleDateFormat sdf = new SimpleDateFormat(DATE_MONTH_PATTERN);
        return sdf.format(new Date());
    }
    /**
     * 判断字符串是否为合法的日期格式
     * @param dateStr 待判断的字符串
     * @return
     */
    public static boolean isValidDate(String dateStr, String sim){
        //判断结果 默认为true
        boolean validDate=true;
        SimpleDateFormat format = new SimpleDateFormat(sim);
        try{
            //增加强判断条件，否则 诸如2022-02-29也可判断出去
            format.setLenient(false);
            Date date =format.parse(dateStr);
        }catch(Exception e){
            validDate=false;
        }
        //由于上述方法只能验证正常的日期格式，像诸如 0001-01-01、11-01-01，10001-01-01等无法校验，此处再添加校验年份是否合法
        String yearStr=dateStr.split("-")[0];
        if(yearStr.startsWith("0")||yearStr.length()!=4){
            validDate=false;
        }
        return validDate;
    }
}
