package com.yifu.cloud.plus.v1.yifu.common.core.util;

import cn.hutool.core.util.NumberUtil;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;

import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.TemporalUnit;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import static java.time.format.DateTimeFormatter.ofPattern;

/**
 * @author fang
 * @Description LocalDateTime 工具类
 */
public class LocalDateTimeUtils {
    private LocalDateTimeUtils() throws IllegalAccessException {
        throw  new IllegalAccessException("LocalDateTimeUtils class");
    }
    /**
     * 日期时间格式yyyy-MM-dd HH:mm:ss
     */
    public static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

    public static final String DATE_TIME_PATTERN_DEFAULT = "yyyy-MM-dd";

    public static final String DATE_SHORT_PATTERN = "yyyyMMdd";

    public static final String YEAR_MONTH_PATTERN = "yyyyMM";

    //Date转换为LocalDateTime
    public static LocalDateTime convertDateToLDT(Date date) {
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    }

    //LocalDateTime转换为Date
    public static Date convertLDTToDate(LocalDateTime time) {
        if (null != time){
            return Date.from(time.atZone(ZoneId.systemDefault()).toInstant());
        }
        return  null;
    }
	public static LocalDateTime convertLocalDateToLDT(LocalDate date) {
		return LocalDateTime.ofInstant(date.atStartOfDay(ZoneOffset.ofHours(8)).toInstant(), ZoneId.systemDefault());
	}

	public static Date convertLDToDate(LocalDate time) {
		if (null != time){
			return Date.from(time.atStartOfDay(ZoneOffset.ofHours(8)).toInstant());
		}
		return  null;
	}

    //获取指定日期的毫秒
    public static Long getMilliByTime(LocalDateTime time) {
        return time.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    //获取指定日期的秒
    public static Long getSecondsByTime(LocalDateTime time) {
        return time.atZone(ZoneId.systemDefault()).toInstant().getEpochSecond();
    }

    //获取指定时间的指定格式
    public static String formatTime(LocalDateTime time, String pattern) {
        return time.format(ofPattern(pattern));
    }

    public static LocalDateTime formatTime(String time, String pattern) {
        Date date = DateUtil.stringToDate(time,pattern);
        if (null != date){
            Instant instant = date.toInstant();
            ZoneId zone = ZoneId.systemDefault();
            return LocalDateTime.ofInstant(instant,zone);
        }
        return null;
    }

    public static String formatDate(LocalDate date, String pattern) {
        return date.format(ofPattern(pattern));
    }

    //获取当前时间的指定格式
    public static String formatNow(String pattern) {
        return formatTime(LocalDateTime.now(), pattern);
    }

    //日期加上一个数,根据field不同加不同值,field为ChronoUnit.*
    public static LocalDateTime plus(LocalDateTime time, long number, TemporalUnit field) {
        return time.plus(number, field);
    }

    //日期减去一个数,根据field不同减不同值,field参数为ChronoUnit.*
    public static LocalDateTime minu(LocalDateTime time, long number, TemporalUnit field) {
        return time.minus(number, field);
    }
    /**
     * Date转LocalDateTime
     *
     * @param date
     *            Date对象
     * @return
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    }

    public static String formatDateTime(LocalDateTime dateTime, String pattern) {
        if (dateTime == null) {
            return null;
        }
        if (pattern == null || pattern.isEmpty()) {
            pattern = DATE_TIME_PATTERN;
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        return dateTime.format(formatter);
    }
    /**
     * 获取两个日期的差  field参数为ChronoUnit.*
     *
     * @param startTime
     * @param endTime
     * @param field     单位(年月日时分秒)
     * @return
     */
    public static long betweenTwoTime(LocalDateTime startTime, LocalDateTime endTime, ChronoUnit field) {
        Period period = Period.between(LocalDate.from(startTime), LocalDate.from(endTime));
        if (field == ChronoUnit.YEARS) {
            return period.getYears();
        }
        if (field == ChronoUnit.MONTHS) {
            return (long)(period.getYears() * 12 + period.getMonths());
        }
        return field.between(startTime, endTime);
    }

    /**
     * 获取一天的开始时间，2017,7,22 00:00
     * @Author fxj
     * @Date 2020-10-14
     * @param time
     * @return
     **/
    public static LocalDateTime getDayStart(LocalDateTime time) {
        return time.withHour(0)
                .withMinute(0)
                .withSecond(0)
                .withNano(0);
    }

    /**
     * 获取一天的结束时间，2017,7,22 23:59:59.999999999
     * @Author fxj
     * @Date 2020-10-14
     * @param time
     * @return
     **/
    public static LocalDateTime getDayEnd(LocalDateTime time) {
        return time.withHour(23)
                .withMinute(59)
                .withSecond(59)
                .withNano(999999999);
    }

    public static  List<String> getMonthFullDayStr(LocalDate startDate,LocalDate endDate, String pattern) {
        List<String> dayStrList = new ArrayList<>();
        DateTimeFormatter dateTimeFormatter = ofPattern(pattern);
        LocalDate tempDate = startDate;
        for(int i=0;endDate.isAfter(tempDate);i++){
            tempDate = startDate.plusDays(i);
            dayStrList.add(tempDate.format(dateTimeFormatter));
        }
        return dayStrList;
    }

    /**
     * @param strDate
     * @param pattern
     * @Author: wangan
     * @Date: 2019/8/22
     * @Description: 校验日期合法性
     * @return: boolean
     **/
    public static boolean isValidDate(String strDate, String pattern) {
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        try {
            // 设置lenient为false. 否则SimpleDateFormat会比较宽松地验证日期，比如2018-02-29会被接受，并转换成2018-03-01
            format.setLenient(false);
            format.parse(strDate);
        } catch (Exception e) {
            return false;
        }
        return true;
    }
    /**
     * 获取time所在月的开始时刻 （1号0点0分0秒）
     * @Author pwang
     * @Date 2019-11-19 18:03
     * @param time
     * @return
     **/
    public static LocalDateTime firstdayOfMonth(LocalDateTime time){
       return getDayStart(time).with(TemporalAdjusters.firstDayOfMonth());
    }
    /**
     * 获取time所在月的结束时刻 （最后一天23点59分59秒）
     * @Author pwang
     * @Date 2019-11-19 18:03
     * @param time
     * @return
     **/
    public static LocalDateTime lastDayOfMonth(LocalDateTime time){
       return getDayEnd(time).with(TemporalAdjusters.lastDayOfMonth());
    }
    /**
     * 获取time所在年的开始时刻 （1月1号0点0分0秒）
     * @Author pwang
     * @Date 2019-11-19 18:03
     * @param time
     * @return
     **/
    public static LocalDateTime firstdayOfYear(LocalDateTime time){
        return getDayStart(time).with(TemporalAdjusters.firstDayOfYear());
    }
    /**
     * 获取time所在年的结束时刻 （最后一天23点59分59秒）
     * @Author pwang
     * @Date 2019-11-19 18:03
     * @param time
     * @return
     **/
    public static LocalDateTime lastDayOfYear(LocalDateTime time){
        return getDayEnd(time).with(TemporalAdjusters.lastDayOfYear());
    }
    /**
     * 月份差
     * @param startMonth
     * @param endMonth
     * @param format (y,M,d元素不可少，否则报错。如yyyyMM少了dd会报错)
     * @return
     */
    public static Integer getBeginOfMonth(String startMonth,String endMonth,String format){
        LocalDate bef = LocalDate.parse(startMonth, ofPattern(format));
        LocalDate aft = LocalDate.parse(endMonth, ofPattern(format));
        return getBeginOfMonth(bef,aft);
    }
    /**
     * 月份差
     * @param startDate
     * @param endDate
     * @return
     */
    public static Integer getBeginOfMonth(LocalDate startDate,LocalDate endDate){
        Period periodTime = Period.between(startDate, endDate);
        int month = periodTime.getMonths() ;
        int years = periodTime.getYears();
        return Math.abs(month + years * 12);
    }
    public static LocalDateTime getNextMonthLocalDateTime(){
        try {
            Date date =DateUtil.getCurrentDateTime();
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            calendar.add(Calendar.MONTH,1);
            calendar.set(Calendar.DATE, calendar.getActualMaximum(Calendar.DATE));
            //获取最终的时间
            Date time = calendar.getTime();
            return time.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        }catch (Exception e){
            return null;
        }
    }
    /**
     * 获取当天凌晨时间
     * @Author pwang
     * @Date 2020-09-10 17:59
     * @param time
     * @return
     **/
    public static LocalDateTime getThatDayStartTime(LocalDateTime time){
        return  LocalDateTime.of(time.toLocalDate(), LocalTime.MIN);
    }
    /**
     * 获取当天凌晨时间
     * @Author pwang
     * @Date 2020-09-10 18:00
     * @param day
     * @return
     **/
    public static LocalDateTime getThatDayStartTime(LocalDate day){
        return  LocalDateTime.of(day, LocalTime.MIN);
    }
    /**
     * 获取今天天凌晨时间
     * @Author pwang
     * @Date 2020-09-10 18:00
     * @param
     * @return
     **/
    public static LocalDateTime getToDayStartTime(){
        return  getThatDayStartTime(LocalDate.now());
    }
    /**
     * 年月拼接成时间 如  202001 转成 LocalDateTime  2020-01-01
     * @Author fxj
     * @Date 2020-12-30
     * @param yearMonth  202001
     * @param patternDefault
     * @return
     **/
    public static LocalDateTime dateOfYearAndMonth(String yearMonth, String patternDefault) {
        if (Common.isEmpty(patternDefault)){
            patternDefault = DATE_SHORT_PATTERN;
        }
        if (Common.isEmpty(yearMonth) ||
            yearMonth.length() != CommonConstants.SIX_INT ||
            !NumberUtil.isInteger(yearMonth)){
            return null;
        }
        return convertDateToLDT(DateUtil.stringToDate(yearMonth+"01",patternDefault));
    }

    /**
     *计算两个时间点的分钟差
     * @Author chenyuxi
     * @param dt1 第一个时间点
     * @param dt2 第二个时间点
     */
    public static int dateDiffByMinute(LocalDateTime dt1, LocalDateTime dt2) {
        return dateDiff(dt1, dt2, 60);
    }

    /**
     *计算两个时间点的小时差
     * @Author chenyuxi
     * @param dt1 第一个时间点
     * @param dt2 第二个时间点
     */
    public static int dateDiffByHour(LocalDateTime dt1, LocalDateTime dt2) {
        return dateDiff(dt1, dt2, 60*60);
    }

    /**
     *计算两个时间点的天数差
     * @Author chenyuxi
     * @param dt1 第一个时间点
     * @param dt2 第二个时间点
     */
    public static int dateDiffByDay(LocalDateTime dt1, LocalDateTime dt2) {
        return dateDiff(dt1, dt2, 60*60*24);
    }

    /**
     *计算两个时间点的时间差
     * @Author chenyuxi
     * @Date 2021-02-25 18:47
     * @param dt1 第一个时间点
     * @param dt2 第二个时间点
     * @return int，即指定要计算的时间差
     */
    private static int dateDiff(LocalDateTime dt1, LocalDateTime dt2, int timeNum) {
        //获取第一个时间点的时间戳对应的秒数
        long t1 = dt1.toEpochSecond(ZoneOffset.ofHours(0));
        //获取第一个时间点在是1970年1月1日后的第几天
        long minute1 = t1 /(timeNum);
        //获取第二个时间点的时间戳对应的秒数
        long t2 = dt2.toEpochSecond(ZoneOffset.ofHours(0));
        //获取第二个时间点在是1970年1月1日后的第几天
        long minute2 = t2/(timeNum);
        //返回两个时间点的分钟差
        return (int)(minute2 - minute1);
    }

    /**
     * @param dateTime
     * @param mnt
     * @Description: 时间加减月份
     * @Author: hgw
     * @Date: 2021/12/20 17:00
     * @return: java.lang.String
     **/
    public static String addMonthByDate(LocalDateTime dateTime, int mnt) {
        if (dateTime == null) {
            return null;
        }
        dateTime = dateTime.plusMonths(mnt);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YEAR_MONTH_PATTERN);
        return dateTime.format(formatter);
    }

	/**
	 * @param time “Unix标准时间戳”是从1970年1月1日(UTC/GMT的午夜)开始所经过的毫秒数，数据类型为整数型
	 * @Description: 将整数型时间毫秒数，转化为LocalDateTime
	 * @Author: hgw
	 * @Date: 2025/10/10 11:27
	 * @return: java.time.LocalDateTime
	 **/
	public static LocalDateTime coverStringToLDT(String time) {
		if (time == null) {
			return null;
		}
		LocalDateTime dateTime;
		try {
			dateTime = Instant.ofEpochMilli(Long.parseLong(time))
					.atZone(ZoneId.systemDefault()) // 使用系统默认时区
					.toLocalDateTime();
			// 使用a进行后续操作
		} catch (NumberFormatException e) {
			dateTime = null;
		}
		return dateTime;
	}
}
