package com.crunii.micro.common.utils;

import com.crunii.micro.common.exception.BusinessException;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;

/**
 * @Author jiang
 * @Description java8日期工具类
 * @Date 2021/9/23
 * @Param  * @param null
 * @return
 */
public class DateUtils {
    //<editor-fold defaultstate="collapsed" desc="delombok">
    @SuppressWarnings("all")
    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DateUtils.class);
    //</editor-fold>

    /**
     * 工具类构造方法私有，禁止实例化
     * 直接调用该类的static方法
     */
    public DateUtils() {
    }

    public static final String DATE_TIME_0 = "000000";
    public static final String DATE_TIME_05 = "yyyyMM";
    public static final String DATE_TIME_06 = "MMdd";
    public static final String DATE_TIME_07 = "MM-dd";
    /**
     * LocalDateTime默认日期时间格式 LocalDateTime
     */
    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_TIME_FORMAT_WITHOUT_SECOND = "yyyy-MM-dd HH:mm";
    public static final String SMS_DATE_TIME_FORMAT = "yyyy年MM月dd日 0时";
    public static final String SMS_DATE_TIME_FORMAT2 = "yyyy年MM月";
    /**
     * DATE_TIME_FORMAT2 描述此常量
     */
    public static final String DEFAULT_DATE_TIME_FORMAT2 = "yyyyMMddHHmmss";
    /**
     * 毫秒时间戳
     */
    public static final String DEFAULT_DATE_TIME_FORMAT3 = "yyyyMMddHHmmssSSS";
    /**
     * 分钟时间戳
     */
    public static final String DEFAULT_DATE_TIME_FORMAT4 = "yyyyMMddHHmm";
    /**
     * LocalDate默认日期格式
     */
    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    public static final String DEFAULT_DATE_FORMAT1 = "yyyy-MM";
    public static final String DEFAULT_DATE_FORMAT2 = "yyyyMMdd";
    /**
     * LocalTime默认时间格式
     */
    public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
    /**
     * 默认LocalDateTime时间格式: yyyy-MM-dd HH:mm:ss
     */
    private static final DateTimeFormatter DEFAULT_DATETIME_FORMATTER = DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT);

    /**
     * 默认LocalDateTime时间格式: yyyy-MM-dd HH:mm
     */
    private static final DateTimeFormatter DATETIME_FORMATTER_WITHOUT_SECOND = DateTimeFormatter.ofPattern(DATE_TIME_FORMAT_WITHOUT_SECOND);
    /**
     * 默认LocalDate时间格式: yyyy-MM-dd
     */
    private static final DateTimeFormatter DEFAULT_DATE_FORMATTER = DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT);
    /**
     * LocalDate时间格式: yyyyMMdd
     */
    private static final DateTimeFormatter DEFAULT_DATE_FORMATTER2 = DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT2);
    /**
     * 默认LocalTime时间格式: HH:mm:ss
     */
    private static final DateTimeFormatter DEFAULT_TIME_FORMATTER = DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT);
    //<editor-fold defaultstate="collapsed" desc="delombok">
    private static final SimpleDateFormat SDF_TIME_SEC = new SimpleDateFormat("yyyyMMddHHmmss");
    //</editor-fold>

    /**
     * 获取yyyyMMddHHmmss格式, 20190218101037 到秒
     *
     * @return
     */
    public static String getCurrentTimeSec() {
        return SDF_TIME_SEC.format(new Date());
    }

    /**
     * date格式转LocalDateTime
     *
     * @param date
     * @return
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        Instant instant = date.toInstant();
        return instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    /**
     * date格式转LocalDate
     *
     * @param date
     * @return
     */
    public static LocalDate dateToLocalDate(Date date) {
        Instant instant = date.toInstant();
        return instant.atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * str转LocalDateTime
     *
     * @param localDateTimeStr 日期字符串，日期格式为yyyy-MM-dd HH:mm:ss
     * @since v1.0
     */
    public static LocalDateTime parseLocalDateTime(String localDateTimeStr) {
        return LocalDateTime.parse(localDateTimeStr, DEFAULT_DATETIME_FORMATTER);
    }

    /**
     * str转LocalDateTime,指定日期格式
     *
     * @param timeStr   日期字符串
     * @param formatter 指定日期格式
     * @since v1.0
     */
    public static LocalDateTime parseLocalDateTime(String timeStr, String formatter) {
        return LocalDateTime.parse(timeStr, DateTimeFormatter.ofPattern(formatter));
    }

    public static LocalDateTime parseLocalDateTime(Timestamp timestamp) {
        return LocalDateTime.ofInstant(timestamp.toInstant(), ZoneId.systemDefault());
    }

    /**
     * LocalDateTime转Str
     *
     * @param localDateTime 日期时间
     * @return 返回格式为yyyy-MM-dd HH:mm:ss字符串
     * @author yanziyu
     * @since v1.0
     */
    public static String formatLocalDateTime(LocalDateTime localDateTime) {
        return DEFAULT_DATETIME_FORMATTER.format(localDateTime);
    }

    public static String formatLocalDateTimeWithoutSecond(LocalDateTime localDateTime) {
        return DATETIME_FORMATTER_WITHOUT_SECOND.format(localDateTime);
    }

    /**
     * LocalDateTime转Str
     *
     * @param localDateTime 日期时间
     * @param formatter     指定的格式
     * @return 返回指定格式的字符串
     * @author yanziyu
     * @since v1.0
     */
    public static String formatLocalDateTime(LocalDateTime localDateTime, String formatter) {
        return DateTimeFormatter.ofPattern(formatter).format(localDateTime);
    }

    /**
     * str转LocalDate
     *
     * @param localDateStr 日期字符串，日期格式为yyyy-MM-dd
     * @author yanziyu
     * @since v1.0
     */
    public static LocalDate parseLocalDate(String localDateStr) {
        return LocalDate.parse(localDateStr, DEFAULT_DATE_FORMATTER);
    }

    /**
     * str转LocalDate,指定日期格式
     *
     * @param localDateStr 日期字符串
     * @param formatter    指定日期格式
     * @author yanziyu
     * @since v1.0
     */
    public static LocalDate parseLocalDate(String localDateStr, String formatter) {
        return LocalDate.parse(localDateStr, DateTimeFormatter.ofPattern(formatter));
    }

    /**
     * LocalDate转默认格式Str
     *
     * @param localDate 日期
     * @return 返回格式为yyyy-MM-dd字符串
     * @author yanziyu
     * @since v1.0
     */
    public static String formatLocalDate(LocalDate localDate) {
        return DEFAULT_DATE_FORMATTER.format(localDate);
    }

    /**
     * LocalDate转默认格式Str
     *
     * @param localDate 日期
     * @return 返回格式为yyyyMMdd字符串
     * @author yanziyu
     * @since v1.0
     */
    public static String formatLocalDate2(LocalDate localDate) {
        return DEFAULT_DATE_FORMATTER2.format(localDate);
    }

    /**
     * LocalDate转指定格式Str
     *
     * @param localDate 日期
     * @param formatter 指定的格式
     * @return 返回指定格式的字符串
     * @author yanziyu
     * @since v1.0
     */
    public static String formatLocalDate(LocalDate localDate, String formatter) {
        return DateTimeFormatter.ofPattern(formatter).format(localDate);
    }

    /**
     * str转LocalTime
     *
     * @param localTimeStr 日期字符串，日期格式为HH:mm:ss
     * @author yanziyu
     * @since v1.0
     */
    public static LocalTime parseLocalTime(String localTimeStr) {
        return LocalTime.parse(localTimeStr, DEFAULT_TIME_FORMATTER);
    }

    /**
     * str转LocalTime,指定日期格式
     *
     * @param localTimeStr 日期字符串
     * @param formatter    指定日期格式
     * @author yanziyu
     * @since v1.0
     */
    public static LocalTime parseLocalTime(String localTimeStr, String formatter) {
        return LocalTime.parse(localTimeStr, DateTimeFormatter.ofPattern(formatter));
    }

    /**
     * @param date
     * @param sourceFormat 本格式  yyyyMMdd
     * @param targetFormat 转后格式 yyyy-mm-dd
     * @return
     */
    public static String dateFormatTurn(String date, String sourceFormat, String targetFormat) {
        DateTimeFormatter sourceFormatFormatter = DateTimeFormatter.ofPattern(sourceFormat);
        DateTimeFormatter targetFormatFormatter = DateTimeFormatter.ofPattern(targetFormat);
        try {
            LocalDate sourceDate = LocalDate.parse(date, sourceFormatFormatter);
            return targetFormatFormatter.format(sourceDate);
        } catch (Exception e) {
            LocalDateTime sourceDate = LocalDateTime.parse(date, sourceFormatFormatter);
            return targetFormatFormatter.format(sourceDate);
        }
    }

    /**
     * LocalTime转默认格式Str
     *
     * @param localTime 日期
     * @return 返回格式为HH:mm:ss字符串
     * @author yanziyu
     * @since v1.0
     */
    public static String formatLocalTime(LocalTime localTime) {
        return DEFAULT_TIME_FORMATTER.format(localTime);
    }

    /**
     * LocalDate转指定格式Str
     *
     * @param localTime 时间
     * @param formatter 指定的格式
     * @return 返回指定格式的字符串
     * @author yanziyu
     * @since v1.0
     */
    public static String formatLocalTime(LocalTime localTime, String formatter) {
        return DateTimeFormatter.ofPattern(formatter).format(localTime);
    }

    /**
     * 获取两个时间之间月数的差异
     *
     * @param observeTime  描述此参数
     * @param forecastTime 描述此参数
     * @return 返回 int 描述此返回参数
     * @author yanziyu
     * @date 20190715 14:05:34
     * @since v1.0
     */
    public static int getMonthBetween(LocalDateTime observeTime, LocalDateTime forecastTime) {
        //开始时间大于结束时间，抛出异常
        if (observeTime.isAfter(forecastTime)) {
            throw new BusinessException("开始时间，大于结束时间");
        }
        int startYear = observeTime.getYear();
        int endYear = forecastTime.getYear();
        int startMonth = observeTime.getMonthValue();
        int endMonth = forecastTime.getMonthValue();
        if (startYear == endYear) {
            return endMonth - startMonth;
        } else {
            return (endYear - startYear - 1) * 12 + (12 - startMonth) + endMonth;
        }
    }

    /**
     * @Description: 使用LocalDateTime计算两个时间的差
     * @Param: []
     * @return: int
     * @Author: Jiangsg
     * @Date: 2021-7-15
     */
    public static void timeDiffer() {
        LocalDateTime now = LocalDateTime.now();
        System.out.println("计算两个时间的差：");
        LocalDateTime end = LocalDateTime.now();
        Duration duration = Duration.between(now, end);
        long days = duration.toDays(); //相差的天数
        long hours = duration.toHours();//相差的小时数
        long minutes = duration.toMinutes();//相差的分钟数
        long millis = duration.toMillis();//相差毫秒数
        long nanos = duration.toNanos();//相差的纳秒数
        System.out.println(now);
        System.out.println(end);
        System.out.println("发送短信耗时【 " + days + "天：" + hours + " 小时：" + minutes + " 分钟：" + millis + " 毫秒：" + nanos + " 纳秒】");
    }

    /**
     * @Description: 使用LocalDateTime计算两个时间的差
     * @Param: []
     * @return: int
     * @Author: Jiangsg
     * @Date: 2021-7-15
     */
    public static Long getDifferDays(Date lastLoginTime) {
        Instant instant = lastLoginTime.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime time = instant.atZone(zoneId).toLocalDateTime();
        LocalDateTime end = LocalDateTime.now();
        Duration duration = Duration.between(time, end);
        return duration.toDays();
    }

    /**
     * 获取月日目录名，例如0101
     *
     * @param localDateTime 描述此参数
     * @return 返回 month day directory name
     * @author yanziyu
     * @date 20181115 10:57:28
     * @since v1.0
     */
    public static String getMonthDayDirectoryName(LocalDateTime localDateTime) {
        return monthDaySupplementZeroLessThanTen(localDateTime.getMonth().getValue()) + monthDaySupplementZeroLessThanTen(localDateTime.getDayOfMonth());
    }

    /**
     * 对小于10的数字进行补0，主要用于月和日的目录名获取
     *
     * @param number 描述此参数
     * @return 返回 string 描述此返回参数
     * @author yanziyu
     * @date 20181115 10:56:26
     * @since v1.0
     */
    public static String monthDaySupplementZeroLessThanTen(int number) {
        return number < 10 ? "0" + number : String.valueOf(number);
    }

    /**
     * 传入的日期，返回MMdd字符串
     *
     * @author
     * @date 20181130 15:28:43
     * @since v1.0
     */
    public static String monthAndDaySupplementZero(LocalDateTime localDateTime) {
        return monthDaySupplementZeroLessThanTen(localDateTime.getMonthValue()) + monthDaySupplementZeroLessThanTen(localDateTime.getDayOfMonth());
    }

    /**
     * localDateTime转换为date
     *
     * @param localDateTime 描述此参数
     * @return 返回 date 描述此返回参数
     * @author yanziyu
     * @date 20180920 11:23:40
     * @since v1.0
     */
    public static Date localDateTimeToDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * localDateTime转换为date
     *
     * @return 返回 date 描述此返回参数
     * @author yanziyu
     * @date 20180920 11:23:40
     * @since v1.0
     */
    public static String getDateTime0(Date date) {
        return DateFormatUtils.format(date, DEFAULT_DATE_TIME_FORMAT4);
    }

    /**
     * LocalDate转换为Date
     *
     * @param localDate 描述此参数
     * @return 返回 date 描述此返回参数
     * @author sunMing
     * @date 20190726
     * @since v1.0
     */
    public static Date localDateToDate(LocalDate localDate) {
        return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
    }

    public static Date parseString(String dateStr, String format) {
        if (StringUtils.isEmpty(dateStr)) {
            log.warn("invalid data,dateStr={}", dateStr);
            return null;
        }
        if (StringUtils.isEmpty(format)) {
            log.warn("invalid format,format={}", format);
            return null;
        }
        DateFormat df = new SimpleDateFormat(format);
        Date date = null;
        try {
            date = df.parse(dateStr);
            if (!dateStr.equals(df.format(date))) {
                date = null;
            }
        } catch (ParseException e) {
            log.error("fail to parse date", e);
        }
        return date;
    }

    /**
     * 将传入的时间转为周一
     *
     * @return 返回 local date time 描述此返回参数
     * @author yanziyu
     * @date 20181129 17:57:58
     * @since v1.0
     */
    public static LocalDateTime getMonday(LocalDateTime localDateTime) {
        int value = localDateTime.getDayOfWeek().getValue();
        return localDateTime.minusDays(value - 1);
    }

    /**
     * 检查是否为2月29日
     *
     * @param forecastTime 预报时间
     * @return 返回 boolean 描述此返回参数
     * @author yanziyu
     * @date 20190821 17:32:34
     * @since v1.0
     */
    public static boolean check229(LocalDateTime forecastTime) {
        return forecastTime.getMonthValue() == 2 && forecastTime.getDayOfMonth() == 29;
    }

    /**
     * 获取当月最后一天的日期字符串
     *
     * @author
     * @date 20190321 14:05:33
     * @since v1.0
     */
    public static String getMonthLastDayNumber(LocalDateTime localDateTime) {
        return monthDaySupplementZeroLessThanTen(localDateTime.plusMonths(1).withDayOfMonth(1).minusDays(1).getDayOfMonth());
    }

    /**
     * 开始时间小于或等于 结束时间
     *
     * @param start 描述此参数
     * @param end   描述此参数
     * @return 返回 boolean 描述此返回参数
     * @author
     * @date 20181105 11:00:15
     * @since v1.0
     */
    public static boolean lessThanOrEqualTime(LocalDateTime start, LocalDateTime end) {
        if (start.isEqual(end)) {
            return true;
        }
        return end.isAfter(start);
    }

    /**
     * 日期加减操作
     *
     * @param date
     * @param field
     * @param value
     * @return
     */
    public static Date add(Date date, int field, int value) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(field, value);
        return cal.getTime();
    }

    /**
     * @Description: 获取前一天时间
     * @Param: []
     * @return: java.util.Date
     * @Author: Jiangsg
     * @Date: 2021-1-11
     */
    public static String dayBefore() {
        Calendar ca = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat(DEFAULT_DATE_FORMAT2);
        ca.setTime(new Date());
        ca.add(Calendar.DATE, -1);
        String format = sdf.format(ca.getTime());
        return format;
    }

    /**
     * @Description: 获取前一天时间结束
     * @Param: []
     * @return: java.util.Date
     * @Author: Jiangsg
     * @Date: 2021-1-11
     */
    public static Date dayBeforeEnd(Long date) {
        Calendar ca = Calendar.getInstance();
        ca.setTime(new Date(date));
        ca.add(Calendar.DATE, -1);
        ca.set(Calendar.HOUR_OF_DAY, 23);
        ca.set(Calendar.MINUTE, 59);
        ca.set(Calendar.SECOND, 59);
        return ca.getTime();
    }

    /**
     * 将日期转换未指定类型的字符串.
     *
     * @param date   要转换的date
     * @param format 格式
     * @return 转换完成的字符串
     */
    public static String formatDate(Date date, String format) {
        if (null == date) {
            return "";
        }
        DateFormat df = new SimpleDateFormat(format);
        return df.format(date);
    }

//    public static String bjDateStr(String datetime, String pattern) {
//        Date dateBj = com.crunii.micro.common.utils.date.DateUtils.parseString(datetime, pattern);
//        dateBj = com.crunii.micro.common.utils.date.DateUtils.add(dateBj, Calendar.HOUR, 8);
//        datetime = com.crunii.micro.common.utils.date.DateUtils
//            .formatDate(dateBj, "yyyy-MM-dd HH:mm:ss");
//        return datetime;
//    }
    //    public static void main(String[] args) {
    //        LocalDateTime nowDayTime = null;
    //        LocalDate beforeDay = LocalDate.now();
    //        nowDayTime = beforeDay.atTime(0, 0, 0);
    //        System.out.println(nowDayTime);
    //    }
    //<editor-fold defaultstate="collapsed" desc="delombok">
    /**
     * 获取北京时间
     *
     * @param datetime 描述此参数
     * @return 返回 string 描述此返回参数
     * @author zhouqi
     * @date 20180627
     * @since v1.0
     */
    //</editor-fold>
    public static String format(Date date, String style) {
        SimpleDateFormat format = new SimpleDateFormat(style);
        return format.format(date);
    }

    /**
     * 将时间格式化成日期yyyyMMdd字符格式
     *
     * @param date
     * @return 指定格式的时间类型字符串 例如(20170109)
     */
    public static String formatToDate(Date date) {
        if (date != null) {
            return format(date, "yyyyMMdd");
        } else {
            return null;
        }
    }

    /**
     * 获取上个月
     *
     * @param month
     * @return
     */
    public static String lastMonth(String month) throws ParseException {
        SimpleDateFormat sf = new SimpleDateFormat("yyyyMM");
        Date date = sf.parse(month);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) - 1); // 设置为上一个月
        date = calendar.getTime();
        return sf.format(date);
    }

    private static AtomicLong atomicTimeMills = new AtomicLong(0);
    private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");

    public static String getNextTime() {
        while (true) {
            long currentMill = atomicTimeMills.get();
            Long currentTimeMillis = Long.parseLong(LocalDateTime.now().format(formatter) + System.nanoTime() % 100);
            if (currentTimeMillis > currentMill && atomicTimeMills.compareAndSet(currentMill, currentTimeMillis)) {
                return currentTimeMillis.toString();
            }
        }
    }

    /**
     * 获取明天 数字类型
     * @return
     */
    public static int getNextDate() {
        // 获取当前日期
        LocalDate currentDate = LocalDate.now();
        // 获取明天的日期
        LocalDate tomorrowDate = currentDate.plusDays(1);
        // 格式化成yyyyMMdd
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        String formattedDate = tomorrowDate.format(formatter);
        // 将格式化后的日期转换成数字
        int numericDate = Integer.parseInt(formattedDate);
        return numericDate;
    }

    /**
     * 获取昨天 数字类型
     * @return
     */
    public static int getYesterdayDate() {
        // 获取当前日期
        LocalDate currentDate = LocalDate.now();
        // 获取明天的日期
        LocalDate tomorrowDate = currentDate.minusDays(1);
        // 格式化成yyyyMMdd
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        String formattedDate = tomorrowDate.format(formatter);
        // 将格式化后的日期转换成数字
        int numericDate = Integer.parseInt(formattedDate);
        return numericDate;
    }

    public static boolean isTodayFirstLogin(Date lastLoginTime) {
        Date currentDate = new Date();
        SimpleDateFormat outputFormat = new SimpleDateFormat("yyyyMMdd");
        String formattedLastLoginDate = outputFormat.format(lastLoginTime);
        String formattedCurrentDate = outputFormat.format(currentDate);
        return formattedLastLoginDate.equals(formattedCurrentDate);
    }

    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        Date time = calendar.getTime();
        System.out.println(isTodayFirstLogin(time));
        ;
    }
}
