package com.malk.utils;

import cn.hutool.core.util.ObjectUtil;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;

import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjusters;
import java.util.Calendar;
import java.util.Date;

/**
 * 时间格式 [Calendar 日历类, Date 是java 8前产物, LocalDateTime]
 */
public abstract class UtilDateTime {

    // todo: 获取次日开启时间, 获取次日结束时间

    public final static String DATE_PATTERN = "yyyy-MM-dd";
    public final static String TIME_PATTERN = "HH:mm:ss";
    public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
    /// ISO-8601的date-time格式: T表示分隔符，Z表示的是UTC
    public final static String DATE_TIME_ISO = "yyyy-MM-dd'T'HH:mm:ssZ";
    public final static String DATE_MSEL_ISO = "yyyy-MM-dd'T'HH:mm:ss.SSS"; // TB


    //// convert ////

    // 将java.util.Date 转换为java8 的java.time.LocalDateTime,默认时区为东8区
    public static LocalDateTime convertToLocalDateTimeFromDate(Date date) {
        return date.toInstant().atOffset(ZoneOffset.of("+8")).toLocalDateTime();
    }

    // 将java8 的 java.time.LocalDateTime 转换为 java.util.Date，默认时区为东8区
    public static Date convertToDateFromLocalDateTime(LocalDateTime localDateTime) {
        return Date.from(localDateTime.toInstant(ZoneOffset.of("+8")));
    }

    // 在start之前, 兼容等于
    public static boolean beforeAndEqual(Date start, Date compare) {
        return start.before(compare) || start.equals(compare);
    }

    // 在end之后, 兼容等于
    public static boolean afterAndEqual(Date end, Date compare) {
        return end.after(compare) || end.equals(compare);
    }

    // 获取时间段内小时
    public static double betweenHour(Temporal startInclusive, Temporal endExclusive) {
        return UtilNumber.formatPrecisionValue(Duration.between(startInclusive, endExclusive).toMinutes() / 60f);
    }

    // 获取上月第一天0点
    public static LocalDateTime firstDayOfLastMonth(LocalDateTime dateTime) {
        int month = dateTime.getMonthValue() - 1;
        int year = dateTime.getYear();
        if (month == 0) {
            month = 12;
            year -= 1;
        }
        return LocalDateTime.of(year, month, 1, 0, 0, 0);
    }

    // 计算时间差和指定如一月最后一天很方便, 如下个月第一天 .... [时间会保留传入时间]
    public static LocalDateTime firstDayOfNextMonth(LocalDateTime dateTime) {
        return dateTime.with(TemporalAdjusters.firstDayOfNextMonth());
    }

    // 获取当天开始时间
    public static LocalDateTime minLocalDateTime(LocalDateTime dateTime) {
        return LocalDateTime.of(dateTime.toLocalDate(), LocalTime.MIN);
    }

    // 获取当天结束时间
    public static LocalDateTime maxLocalDateTime(LocalDateTime dateTime) {
        return LocalDateTime.of(dateTime.toLocalDate(), LocalTime.MAX);
    }

    // 当前时间时间戳
    public static long getLocalDateTimeTimeStamp() {
        return LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
    }

    // 转中国时区时间戳
    public static long getLocalDateTimeTimeStamp(LocalDateTime dataTime) {
        return dataTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
    }

    // 时间戳转为本地时间日期
    public static LocalDateTime getLocalDateTimeFromTimestamp(long millisecond) {
        return LocalDateTime.ofEpochSecond(millisecond / 1000, 0, ZoneOffset.ofHours(8));
    }

    //// Date ////

    public static String formatDateTime(Date dateTime) {
        if (ObjectUtil.isNull(dateTime)) return "";
        return new SimpleDateFormat(DATE_TIME_PATTERN).format(dateTime);
    }

    public static String formatDate(Date dateTime) {
        return new SimpleDateFormat(DATE_PATTERN).format(dateTime);
    }

    public static String formatTime(Date dateTime) {
        return new SimpleDateFormat(TIME_PATTERN).format(dateTime);
    }

    public static String format(Date dateTime, String pattern) {
        return new SimpleDateFormat(pattern).format(dateTime);
    }

    public static String formatQuarter(Date date) {
        // 月份从0开始
        return date.getYear() + "-" + (date.getMonth() / 3 + 1);
    }

    @SneakyThrows
    public static Date parseDateTime(String dateStr) {
        if (StringUtils.isBlank(dateStr)) {
            return new Date();
        }
        return new SimpleDateFormat(DATE_TIME_PATTERN).parse(dateStr);
    }

    @SneakyThrows
    public static Date parseDate(String dateStr) {
        return new SimpleDateFormat(DATE_PATTERN).parse(dateStr);
    }

    @SneakyThrows
    public static Date parseTime(String dateStr) {
        return new SimpleDateFormat(TIME_PATTERN).parse(dateStr);
    }

    @SneakyThrows
    public static Date parse(String dateStr, String pattern) {
        return new SimpleDateFormat(pattern).parse(dateStr);
    }

    //// LocalDateTime ////

    public static String formatLocalDateTime(LocalDateTime dateTime) {
        if (ObjectUtil.isNull(dateTime)) return "";
        return DateTimeFormatter.ofPattern(DATE_TIME_PATTERN).format(dateTime);
    }

    public static String formatLocalDate(LocalDate dateTime) {
        return DateTimeFormatter.ofPattern(DATE_PATTERN).format(dateTime);
    }

    public static String formatLocalTime(LocalTime dateTime) {
        return DateTimeFormatter.ofPattern(TIME_PATTERN).format(dateTime);
    }

    public static String formatLocal(LocalDateTime dateTime, String pattern) {
        return DateTimeFormatter.ofPattern(pattern).format(dateTime);
    }

    public static String formatLocal(LocalDate dateTime, String pattern) {
        return DateTimeFormatter.ofPattern(pattern).format(dateTime);
    }

    public static String formatLocalQuarter(LocalDate date) {
        // 月份从1开始
        return date.getYear() + "-Q" + ((date.getMonth().getValue() - 1) / 3 + 1);
    }

    public static LocalDateTime parseLocalDateTime(String dateStr) {
        if (StringUtils.isBlank(dateStr)) {
            return LocalDateTime.now();
        }
        return LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern(DATE_TIME_PATTERN));
    }

    public static LocalDate parseLocalDate(String dateStr) {
        return LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(DATE_PATTERN));
    }

    public static LocalTime parseLocalTime(String dateStr) {
        return LocalTime.parse(dateStr, DateTimeFormatter.ofPattern(TIME_PATTERN));
    }

    public static LocalTime parseLocal(String dateStr, String pattern) {
        return LocalTime.parse(dateStr, DateTimeFormatter.ofPattern(pattern));
    }

    //// Calendar ////

    // 获取上月最后一天
    public static String lastDayOfNextMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        // 指定日期月份减去一
        cal.add(Calendar.MONTH, -1);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        cal.roll(Calendar.DAY_OF_MONTH, -1);
        return formatDate(cal.getTime()) + " 23:59:59";
    }

    // 获取上月第一天
    public static String firstDayOfNextMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        // 指定日期月份减去一
        cal.add(Calendar.MONTH, -1);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        return formatDate(cal.getTime()) + " 00:00:00";
    }
}
