package com.heyu.api.data.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;

import java.lang.management.ManagementFactory;
import java.sql.Time;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.util.*;

/**
 * 时间工具类
 *
 * @author linzi
 */
@Slf4j
public class DateUtils  extends org.apache.commons.lang3.time.DateUtils {
    public static String YYYY = "yyyy";

    public static String YYYY_MM = "yyyy-MM";

    public static String YYYY_MM_DD = "yyyy-MM-dd";

    public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

    /**
     * yyyyMMddHHmmss
     */
    public static final String yyyyMM                = "yyyyMM";

    /**
     * yyyyMMddHHmmss
     */
    public static final String yyyyMMdd                = "yyyyMMdd";

    /**
     * yyyyMMddHHmmss
     */
    public static final String yyyyMMddHH                = "yyyyMMddHH";

    /**
     * yyyyMMddHHmmss
     */
    public static final String yyyyMMddHHmm                = "yyyyMMddHHmm";

    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
    public static String YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";
    public static String YYYY_MM_DD_HH = "yyyy-MM-dd HH";


    public static String YYYY_MM_DD_HH_MM_UTC = "yyyy-MM-ddTHH:mm";

    public static String YYYY_MM_DD_HH_MM_SS_SSS = "yyyy-MM-dd HH:mm:ss.SSS";

    public static String YYYY_MM_DD_HH_MM_SS_SSS_str = "yyyy_MM_dd_HH_mm_ss_SSS";

    public static String YYYY_MM_DD_DOT = "yyyy.MM.dd";
    private static String[] parsePatterns = {
            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};


    public static String HH = "HH";

    /**
     * 获取当前Date型日期
     *
     * @return Date() 当前日期
     */
    public static Date getNowDate() {
        return new Date();
    }

    /**
     * 获取当前日期, 默认格式为yyyy-MM-dd
     *
     * @return String
     */
    public static String getDate() {
        return dateTimeNow(YYYY_MM_DD);
    }

    public static final String getTime() {
        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
    }

    public static final String dateTimeNow() {
        return dateTimeNow(YYYYMMDDHHMMSS);
    }

    public static final String dateTimeNow(final String format) {
        return parseDateToStr(format, new Date());
    }

    public static final String dateTime(final Date date) {
        return parseDateToStr(YYYY_MM_DD, date);
    }

    public static final String parseDateToStr(final String format, final Date date) {
        if (Objects.isNull(date)) {
            return "";
        }
        return new SimpleDateFormat(format).format(date);
    }

    public static final Date dateTime(final String format, final String ts) {
        try {
            return new SimpleDateFormat(format).parse(ts);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 日期路径 即年/月/日 如2018/08/08
     */
    public static final String datePath() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyy/MM/dd");
    }

    /**
     * 日期路径 即年/月/日 如20180808
     */
    public static final String dateTime() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyyMMdd");
    }



    /**
     * 获取服务器启动时间
     */
    public static Date getServerStartDate() {
        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
        return new Date(time);
    }


    public static Date getBeforeMinute(Date date, int minute) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MINUTE, -minute);
        Date beforeDate = calendar.getTime();
        return beforeDate;
    }

    /**
     * 计算两个时间差
     */
    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 + "分钟";
    }

    /**
     * 获取时间角分符号值，单位分秒
     *
     * @param second
     * @return
     */
    public static String getDatePrime(Integer second) {
        if (Objects.isNull(second)) {
            return "0´0″";
        }
        Time time = getTime(second);
        int hour = time.getHours();
        int minuteRes = time.getMinutes();
        int secondRes = time.getSeconds();
        String hourStr = "";
        if (time.compareTo(new Time(1, 0, 0)) == 0) {
            minuteRes = second / 60;
        } else if (hour > 0) {
            hourStr = hour + "h";
            return hourStr + minuteRes + "´";
        }
        return hourStr + minuteRes + "´" + secondRes + "″";
    }

    public static Time getTime(Integer second) {
        if (Objects.isNull(second)) {
            return new Time(0, 0, 0);
        }
        LocalTime of = LocalTime.of(0, 0, 0);
        LocalTime localTime = of.plusSeconds(second);
        return new Time(localTime.getHour(), localTime.getMinute(), localTime.getSecond());
    }


    /**
     * 日期型字符串转化为日期 格式
     */
    public static Date parseDate(Object str) {
        if (str == null) {
            return null;
        }
        try {
            return parseDate(str.toString(), parsePatterns);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * Get start of date.
     *
     * @param date Date
     * @return Date Date
     */
    public static Date getStartOfDate(final Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        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();
    }
    /**
     * Get start of date.
     *
     * @param date     Date
     * @param timeZone
     * @return Date Date
     */
    public static Date getStartOfDate(Date date, TimeZone timeZone) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        long offset = TimeZone.getDefault().getOffset(Calendar.ZONE_OFFSET) - timeZone.getOffset(Calendar.ZONE_OFFSET);
        calendar.add(Calendar.MILLISECOND,(int)offset);
        return calendar.getTime();
    }

    /**
     * 一天的结束时间，【注：只精确到毫秒】
     *
     * @param date
     * @return
     */
    public static Date getEndOfDate(final Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        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();
    }
    /**
     * Get start of date.
     *
     * @param date Date
     * @return Date Date
     */
    public static Date getEndOfDate(Date date, TimeZone timeZone) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        long offset = TimeZone.getDefault().getOffset(Calendar.ZONE_OFFSET) - timeZone.getOffset(Calendar.ZONE_OFFSET);
        calendar.add(Calendar.MILLISECOND,(int)offset);
        return calendar.getTime();
    }

    /**
     * 一天的结束时间，【注：只精确到毫秒】
     *
     * @param date
     * @return
     */
    public static Date getEndOfDateEndWithSecond(final Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        return calendar.getTime();
    }

    public static Date toDate(LocalDateTime localDateTime) {
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = localDateTime.atZone(zoneId);

        Date date = Date.from(zdt.toInstant());
        return date;
    }

    public static Date toDate(LocalDateTime localDateTime,ZoneId zoneId) {
        ZonedDateTime zdt = localDateTime.atZone(zoneId);

        Date date = Date.from(zdt.toInstant());
        return date;
    }


    public static LocalDate toLocalDate(Date date) {
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();

        // atZone()方法返回在指定时区从此Instant生成的ZonedDateTime。
        LocalDate localDate = instant.atZone(zoneId).toLocalDate();
        return localDate;
    }

    public static LocalDateTime toLocalDateTime(Date date) {
        ZoneId defaultZoneId = ZoneId.systemDefault();
        LocalDateTime dateTime = LocalDateTime.ofInstant(date.toInstant(), defaultZoneId);
        return dateTime;
    }

    public static final Date parseStr2Date(String value, final String format) {
        if (Objects.isNull(value)) {
            return null;
        }
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            return sdf.parse(value);
        } catch (ParseException e) {

        }
        return null;
    }

    /**
     * 通过时区获取时间
     *
     * @param date
     * @param timeZone
     */
    public static String parseDateToStrByTimeZone(String format, Date date, TimeZone timeZone) {
        if (Objects.isNull(date)) {
            return "";
        }
        if (StringUtils.isEmpty(format)) {
            format = "yyyy-MM-dd HH:mm:ss";
        }
        SimpleDateFormat df = new SimpleDateFormat(format);
        df.setTimeZone(timeZone);
        return df.format(date);
    }

    /**
     * 通过时区获取时间
     *
     * @param date
     * @param timeZone
     */
    public static String getDateByTimeZone(Date date, TimeZone timeZone) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        format.setTimeZone(timeZone);
        return format.format(date);
    }

    /**
     * 通过时区获取时间
     *
     * @param date
     * @param timeZone
     */
    public static String getDate3ByTimeZone(Date date, TimeZone timeZone) {
        if (Objects.isNull(date)) {
            return null;
        }
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        format.setTimeZone(timeZone);
        String dataStr = format.format(date);
        return dataStr;
    }

    /**
     * 通过时区获取时间
     *
     * @param date
     * @param timeZone
     */
    public static String getDate3ByTimeZone(Date date, TimeZone timeZone, String formatStr) {
        if (Objects.isNull(date)) {
            return null;
        }
        SimpleDateFormat format = new SimpleDateFormat(formatStr);
        format.setTimeZone(timeZone);
        String dataStr = format.format(date);
        return dataStr;
    }


    public static Date formateDate(String gmtCreate, String yyyyMmDdHhMmSs) {
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(yyyyMmDdHhMmSs);
            return simpleDateFormat.parse(gmtCreate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }


    public static Date formateDate(Date gmtCreate, String yyyyMmDdHhMmSs) {
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(yyyyMmDdHhMmSs);
            String b = simpleDateFormat.format(gmtCreate);
            return simpleDateFormat.parse(b);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }



    public static String formateDateStr(Date gmtCreate, String yyyyMmDdHhMmSs) {
        try {
            if(gmtCreate == null || StringUtils.isEmpty(yyyyMmDdHhMmSs)){
                return null;
            }
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(yyyyMmDdHhMmSs);
            String b = simpleDateFormat.format(gmtCreate);
            return b ;
        } catch (Exception e) {
            log.error("异常",e);
        }
        return null;
    }


    /**
     * >
     */
    public static boolean gt(Date date, Date endTime) {
        if (date.getTime() > endTime.getTime()) {
            return true;
        }
        return false;
    }

    /**
     * >
     */
    public static boolean ge(Date date, Date endTime) {
        if (date.getTime() >= endTime.getTime()) {
            return true;
        }
        return false;
    }

    /**
     * >
     */
    public static boolean lt(Date date, Date endTime) {
        if (date.getTime() < endTime.getTime()) {
            return true;
        }
        return false;
    }

    public static boolean le(Date date, Date endTime) {
        if (date.getTime() <= endTime.getTime()) {
            return true;
        }
        return false;
    }

    public static Date formatMinites(Date date) {
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(YYYY_MM_DD_HH_MM);
            String a = simpleDateFormat.format(date);
            return simpleDateFormat.parse(a);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        return null;
    }

    // ==
    public static boolean eq(Date date1, Date date2) {
        if (date1.getTime() == date2.getTime()) {
            return true;
        }
        return false;
    }


    /**
     * judge the srcDate is between startDate and endDate
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static int betweenSecond(Date startDate, Date endDate) {
        if(startDate == null || endDate==null){
            return -1 ;
        }
        Long a = endDate.getTime() - startDate.getTime();
        return (int) (a / 1000);
    }

    /**
     * yyyyMMdd
     */
    public static final String DEFAULT_PATTERN = "yyyyMMdd";

    public static String dateStr(Date date, String f) {
        SimpleDateFormat format = new SimpleDateFormat(f);
        if (date != null) {
            String str = format.format(date);
            return str;
        }
        return "";
    }

    public static String dateStr7(Date date) {
        return dateStr(date, DEFAULT_PATTERN);
    }


    public static int daysBetween(Date date1, Date date2) {
        DateFormat sdf = new SimpleDateFormat(DEFAULT_PATTERN);
        Calendar cal = Calendar.getInstance();
        try {
            Date d1 = sdf.parse(dateStr7(date1));
            Date d2 = sdf.parse(dateStr7(date2));
            cal.setTime(d1);
            long time1 = cal.getTimeInMillis();
            cal.setTime(d2);
            long time2 = cal.getTimeInMillis();
            return Integer.parseInt(String.valueOf((time2 - time1) / 86400000L));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return 0;
    }


    public static int daysBetweenYYYYMMDD(Date date1, Date date2) {
        return daysBetween(DateUtils.formateDate(date1,DateUtils.YYYY_MM_DD),DateUtils.formateDate(date2,DateUtils.YYYY_MM_DD));
    }



    public static int betweenMinutes(Date startDate, Date endDate) {
        Long a = endDate.getTime() - startDate.getTime();
        return (int) (a / (1000 * 60));
    }


    public static int betweenHours(Date startDate, Date endDate) {
        Long a = endDate.getTime() - startDate.getTime();
        return (int) (a / (1000 * 60 * 60));
    }

    /**
     * Get start of date.
     *
     * @param date Date
     * @return Date Date
     */
    public static Date startOfDate(final Date date) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.setTime(date);

        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);

        return new Date(cal.getTime().getTime());
    }


    /**
     * 一天的结束时间，【注：只精确到毫秒】
     *
     * @param date
     * @return
     */
    public static Date endOfDate(final Date date) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.setTime(date);

        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        cal.set(Calendar.MILLISECOND, 999);

        return new Date(cal.getTime().getTime());
    }

    public static Date convertLocalDateTime2Date(LocalDateTime localDateTime) {
        if (localDateTime == null) {
            return null;
        }
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);
        Instant instant = zonedDateTime.toInstant();
        return Date.from(instant);

    }

    public static Date getDate(String date) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS);
        try {
            return simpleDateFormat.parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }




    public static long getTime(Date date) {
        return date.getTime() - 28800000;
    }

    public static boolean isBetween(Date date, Date start, Date end) {
        return date.after(start) && date.before(end);
    }

    /**
     * between 包括边界
     *
     * @param date
     * @param start
     * @param end
     * @return
     */
    public static boolean isBetweenE(Date date, Date start, Date end) {
        if (Objects.isNull(date)) {
            return false;
        }
        if (Objects.isNull(start) || Objects.isNull(end)) {
            return false;
        }
        return date.compareTo(start) >= 0 && date.compareTo(end) <= 0;


    }

    public static Integer getCurrentHH() {
        SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("HH");
        String hh = simpleDateFormat1.format(new Date());
        if (hh.startsWith("0")) {
            hh = hh.substring(1, hh.length());
        }
        return NumberUtils.objToIntDefault(hh, 0);

    }



    public static String toHMS(Integer runTimeMillisecond) {
        if (Objects.isNull(runTimeMillisecond) || runTimeMillisecond == 0) {
            return "";
        }
        long days = runTimeMillisecond / (1000 * 60 * 60 * 24);
        long hours = (runTimeMillisecond % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60);
        long minutes = (runTimeMillisecond % (1000 * 60 * 60)) / (1000 * 60);
        long seconds = (runTimeMillisecond % (1000 * 60)) / 1000;
        long millisecond = (runTimeMillisecond % (1000));
        String timeStr = "";
        if (days > 0) {
            timeStr = timeStr + days + "d";
        }
        if (hours > 0) {
            timeStr = timeStr + hours + "h";
        }
        if (minutes > 0) {
            timeStr = timeStr + minutes + "min";
        }
        if (seconds > 0) {
            timeStr = timeStr + seconds + "s";
        }
        if (millisecond > 0) {
            timeStr = timeStr + millisecond + "ms";
        }
        return timeStr;
    }

    public static String getDateYYYY_MM_DD_HH_MM_SS() {

        return formateDateStr(new Date(),DateUtils.YYYY_MM_DD_HH_MM_SS);
    }


    public Date LocalDateTime2Date(LocalDateTime localDateTime) {
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);
        Instant instant = zonedDateTime.toInstant();
        Date date = Date.from(instant);
        return date;
    }



    /**
     * 获取当前最后一秒的时间
     * @param date
     * @return
     */
    public static int getLastSecondMillis() {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
            Date currentDate = new Date();
            String endDate = sdf.format(currentDate) + ":59.999";
            log.info("getBetweenSecond currentDate:" + sdf1.format(currentDate) + " endDate:" + endDate);
            Date end = sdf1.parse(endDate);
            return (int)(end.getTime() - currentDate.getTime());
        } catch (ParseException e) {
            log.error("getLastSecond异常", e);
        }
        return 0;
    }



    /**
     * Format date as given date format.
     *
     * @param date 日期
     * @return 格式化后的日期字符串
     */
    public static String formatDate(final Date date, String format) {
        return new SimpleDateFormat(format).format(date);
    }



    /**
     * 获取当前最后一秒的时间
     * @return
     */
    public static int betweenMillisSecond(Date startDate, Date endDate) {
        try {
            return (int)(endDate.getTime() - startDate.getTime());
        } catch (Exception e) {
            log.error("betweenMillis", e);
        }
        return 0;
    }



}
