package com.yifu.cloud.plus.v1.yifu.insurances.util;

import cn.hutool.core.date.DateUtil;
import com.yifu.cloud.plus.v1.yifu.common.core.util.Common;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.chrono.ChronoLocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

/**
 * @author licancan
 * @description 日期工具类
 * @date 2022-07-19 14:20:54
 */
public class LocalDateUtil {
	/**
	 * 年格式：yyyy
	 */
	public static final String NORM_YEAR_PATTERN = "yyyy";
	/**
	 * 年月格式：yyyy-MM
	 */
	public static final String NORM_MONTH_PATTERN = "yyyy-MM";
	/**
	 * 标准日期格式：yyyy-MM-dd
	 */
	public static final String NORM_DATE_PATTERN = "yyyy-MM-dd";
	/**
	 * 标准时间格式：HH:mm:ss
	 */
	public static final String NORM_TIME_PATTERN = "HH:mm:ss";
	/**
	 * 标准日期时间格式，精确到分：yyyy-MM-dd HH:mm
	 */
	public static final String NORM_DATETIME_MINUTE_PATTERN = "yyyy-MM-dd HH:mm";
	/**
	 * 标准日期时间格式，精确到秒：yyyy-MM-dd HH:mm:ss
	 */
	public static final String NORM_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

	/**
	 * 判断是否是日期
	 *
	 * @author licancan
	 * @param strDate
	 * @return {@link Boolean}
	 */
	public static Boolean isDate(String strDate,String pattern){
		if (Common.isEmpty(strDate)){
			return false;
		}
		try {
			DateFormat dateFormat = new SimpleDateFormat(pattern);
			Date date = dateFormat.parse(strDate);
			Calendar cal = Calendar.getInstance();
			cal.setTime(date);
			return true;
		}catch (ParseException pe){
			//System.out.println("日期解析异常，返回false")
			return false;
		}
	}

	/**
	 * 字符串格式的日期转LocalDate
	 *
	 * @author licancan
	 * @param strDate
	 * @return {@link LocalDate}
	 */
	public static LocalDate parseLocalDate(String strDate){
		try {
			if (isDate(strDate,NORM_DATE_PATTERN)){
				DateFormat dateFormat = new SimpleDateFormat(NORM_DATE_PATTERN);
				Date date = dateFormat.parse(strDate);
				return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
			}
			return null;
		}catch (Exception e){
			//System.out.println("字符串格式的日期转LocalDate失败")
			return null;
		}
	}

	/**
	 * 判断时间是否是将来时间（大于当天）
	 *
	 * @author licancan
	 * @param strDate
	 * @return {@link boolean}
	 */
	public static boolean isFutureDate(String strDate){
		boolean flag = false;
		//在日期字符串非空时执行
		if (!Common.isEmpty(strDate)) {
			//今日的开始时间
			Date nowDate = new Date();
			Date pastDate = null;
			//格式化日期
			SimpleDateFormat sdf = new SimpleDateFormat(NORM_DATE_PATTERN, Locale.CHINA);
			try {
				//将字符串转为日期格式，如果此处字符串为非合法日期就会抛出异常。
				pastDate = sdf.parse(strDate);
				//调用Date里面的after方法来做判断
				flag = pastDate.after(nowDate);
				/*if (flag)
					System.out.println("该日期晚于今日")
				}else
					System.out.println("该日期早于今日")
				}*/
			} catch (ParseException e) {
				e.printStackTrace();
			}
		}
		//else {
			//System.out.println("日期参数不可为空")
		//}
		return flag;
	}

	/**
	 * 定时任务判断是否过期专用方法
	 *
	 * @author licancan
	 * @param strDate
	 * @return {@link boolean}
	 */
	public static boolean isOverdueDate(String strDate){
		boolean flag = false;
		//在日期字符串非空时执行
		if (!Common.isEmpty(strDate)) {
			//这里需要把传进来的日期加上23:59:59，来判断是否过期
			strDate = strDate + " 23:59:59";
			//今日的开始时间
			Date nowDate = new Date();
			Date pastDate = null;
			//格式化日期
			SimpleDateFormat sdf = new SimpleDateFormat(NORM_DATETIME_PATTERN, Locale.CHINA);
			try {
				//将字符串转为日期格式，如果此处字符串为非合法日期就会抛出异常。
				pastDate = sdf.parse(strDate);
				//调用Date里面的after方法来做判断
				flag = pastDate.after(nowDate);
				/*if (flag)
					System.out.println("该日期晚于今日")
				}else
					System.out.println("该日期早于今日")
				}*/
			} catch (ParseException e) {
				e.printStackTrace();
			}
		}/*else
			System.out.println("日期参数不可为空")
		}*/
		return flag;
	}

	/**
	 * 比较两个时间的早晚
	 *
	 * @author licancan
	 * @param startDate 开始日期
	 * @param endDate 结束日期
	 * @return {@link boolean}
	 */
	public static boolean compareDate(String startDate,String endDate){
		boolean flag = false;
		//在日期字符串非空时执行
		if (!Common.isEmpty(startDate) && !Common.isEmpty(endDate)) {
			Date parseStartDate = null;
			Date parseEndDate = null;
			//格式化日期
			SimpleDateFormat sdf = new SimpleDateFormat(NORM_DATE_PATTERN, Locale.CHINA);
			try {
				//将字符串转为日期格式，如果此处字符串为非合法日期就会抛出异常。
				parseStartDate = sdf.parse(startDate);
				parseEndDate = sdf.parse(endDate);
				//调用Date里面的before方法来做判断
				flag = parseStartDate.before(parseEndDate);
				/*if (flag)
					System.out.println("开始日期早于结束日期")
				}else {
					System.out.println("开始日期晚于结束日期")
				}*/
			} catch (ParseException e) {
				e.printStackTrace();
			}
		}/*else
			System.out.println("日期参数不可为空")
		}*/
		return flag;
	}

	/**
	 * 判断传入的月份是否大于等于本月（结算月份 >= 派单月份）
	 *
	 * @author licancan
	 * @param strMonth 传入的月份
	 * @return {@link boolean}
	 */
	public static boolean isCurrentOrFutureMonth(String strMonth){
		boolean flag = false;
		//在日期字符串非空时执行
		if (!Common.isEmpty(strMonth)) {
			SimpleDateFormat sdf = new SimpleDateFormat(NORM_MONTH_PATTERN, Locale.CHINA);
			try {
				//当前时间
				Calendar cal1 = Calendar.getInstance();
				//传入的字符串解析时间
				Calendar cal2 = Calendar.getInstance();
				Date parseDate = sdf.parse(strMonth);
				cal2.setTime(parseDate);
				if (cal1 == null || cal2 == null) {
					throw new IllegalArgumentException("The date must not be null");
				}
				if (cal2.get(Calendar.YEAR) > cal1.get(Calendar.YEAR)){
					flag = true;
				}else if(cal2.get(Calendar.YEAR) == cal1.get(Calendar.YEAR) && cal2.get(Calendar.MONTH) >= cal1.get(Calendar.MONTH)){
					flag = true;
				}
			} catch (ParseException e) {
				e.printStackTrace();
			}
		}/*else {
			System.out.println("年月参数不可为空");
		}*/
		return flag;
	}

	/**
	 * 计算相差多少天,如果开始时间晚于结束时间会对调
	 *
	 * @author licancan
	 * @param startDate
	 * @param endDate
	 * @return {@link long}
	 */
	public static long betweenDay(String startDate,String endDate){
		long dif = 0;
		//在日期字符串非空时执行
		if (!Common.isEmpty(startDate) && !Common.isEmpty(endDate)) {
			Date parseStartDate = null;
			Date parseEndDate = null;
			//格式化日期
			SimpleDateFormat sdf = new SimpleDateFormat(NORM_DATE_PATTERN, Locale.CHINA);
			try {
				//将字符串转为日期格式，如果此处字符串为非合法日期就会抛出异常。
				parseStartDate = sdf.parse(startDate);
				parseEndDate = sdf.parse(endDate);
				//调用hutool里面的DateUtil.betweenDay方法来做判断
				dif = DateUtil.betweenDay(parseStartDate, parseEndDate, true);
			} catch (ParseException e) {
				e.printStackTrace();
			}
		}/*else
			System.out.println("日期参数不可为空")
		}*/
		return dif + 1;
	}

	/**
	 * 计算相差月份,如果开始时间晚于结束时间会对调
	 * 公式：(endYear - starYear) * 12 + endMonth - startMonth + (endDay >= startDay ? 1 : 0)
	 * @author licancan
	 * @param startDate
	 * @param endDate
	 * @return {@link long}
	 */
	public static long betweenMonth(String startDate,String endDate){
		long dif = 0;
		//在日期字符串非空时执行
		if (!Common.isEmpty(startDate) && !Common.isEmpty(endDate)) {
			Date parseStartDate = null;
			Date parseEndDate = null;
			//格式化日期
			SimpleDateFormat sdf = new SimpleDateFormat(NORM_DATE_PATTERN, Locale.CHINA);
			try {
				//将字符串转为日期格式，如果此处字符串为非合法日期就会抛出异常。
				parseStartDate = sdf.parse(startDate);
				parseEndDate = sdf.parse(endDate);

				//如果开始时间晚于结束时间对调
				if (parseStartDate.after(parseEndDate)) {
					Date t = parseStartDate;
					parseStartDate = parseEndDate;
					parseEndDate = t;
				}

				Calendar starCalendar = Calendar.getInstance();
				starCalendar.setTime(parseStartDate);
				Calendar endCalendar = Calendar.getInstance();
				endCalendar.setTime(parseEndDate);
				int starYear = starCalendar.get(Calendar.YEAR);
				int startMonth = starCalendar.get(Calendar.MONTH);
				int startDay = starCalendar.get(Calendar.DATE);
				int endYear = endCalendar.get(Calendar.YEAR);
				int endMonth = endCalendar.get(Calendar.MONTH);
				int endDay = endCalendar.get(Calendar.DATE);
				dif = (endYear - starYear) * 12 + endMonth - startMonth + (endDay >= startDay ? 1 : 0);
			} catch (ParseException e) {
				e.printStackTrace();
			}
		}/*else
			System.out.println("日期参数不可为空")
		}*/
		return dif;
	}
	/**
	 * @Author fxj
	 * @Description
	 * 	计算相差月份, 如果开始时间晚于结束时间会对调--纯享版，不+1
	 * 	公式：(endYear - starYear) * 12 + endMonth - startMonth
	 * @Date 17:05 2026/1/20
	 * @Param
	 * @return
	**/
	public static long betweenMonthTwo(String startDate,String endDate){
		long dif = 0;
		//在日期字符串非空时执行
		if (!Common.isEmpty(startDate) && !Common.isEmpty(endDate)) {
			Date parseStartDate = null;
			Date parseEndDate = null;
			//格式化日期
			SimpleDateFormat sdf = new SimpleDateFormat(NORM_DATE_PATTERN, Locale.CHINA);
			try {
				//将字符串转为日期格式，如果此处字符串为非合法日期就会抛出异常。
				parseStartDate = sdf.parse(startDate);
				parseEndDate = sdf.parse(endDate);

				//如果开始时间晚于结束时间对调
				if (parseStartDate.after(parseEndDate)) {
					Date t = parseStartDate;
					parseStartDate = parseEndDate;
					parseEndDate = t;
				}

				Calendar starCalendar = Calendar.getInstance();
				starCalendar.setTime(parseStartDate);
				Calendar endCalendar = Calendar.getInstance();
				endCalendar.setTime(parseEndDate);
				int starYear = starCalendar.get(Calendar.YEAR);
				int startMonth = starCalendar.get(Calendar.MONTH);
				int endYear = endCalendar.get(Calendar.YEAR);
				int endMonth = endCalendar.get(Calendar.MONTH);
				dif = (endYear - starYear) * 12 + endMonth - startMonth;
			} catch (ParseException e) {
				e.printStackTrace();
			}
		}
		return dif;
	}

	/**
	 * 计算两个日期之间的月数（Excel DATEDIF逻辑）
	 * @param startDateStr 开始日期，格式：yyyy/MM/dd
	 * @param endDateStr 结束日期，格式：yyyy/MM/dd
	 * @return 月数（整月数 + 1）
	 */
	public static int calculateMonths(String startDateStr, String endDateStr) {
		// 定义日期格式
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

		// 解析日期
		LocalDate startDate = LocalDate.parse(startDateStr, formatter);
		LocalDate endDate = LocalDate.parse(endDateStr, formatter);

		// 计算整月数（Excel DATEDIF的"m"参数逻辑）
		int monthsBetween = calculateFullMonths(startDate, endDate);

		// 加1（根据Excel公式要求）
		return monthsBetween + 1;
	}

	/**
	 * 计算两个日期之间的整月数（模仿Excel DATEDIF的"m"参数）
	 */
	private static int calculateFullMonths(LocalDate startDate, LocalDate endDate) {
		// 如果开始日期晚于结束日期，返回0
		if (startDate.isAfter(endDate)) {
			return 0;
		}

		// 计算年份和月份的差值
		int years = endDate.getYear() - startDate.getYear();
		int months = endDate.getMonthValue() - startDate.getMonthValue();
		int totalMonths = years * 12 + months;

		// 如果结束日的日份小于开始日的日份，减1个月
		// 这是Excel DATEDIF的规则：不足整月的不计入
		if (endDate.getDayOfMonth() < startDate.getDayOfMonth()) {
			totalMonths--;
		}

		return totalMonths;
	}
	/**
	 * 判断两个时间段是否有交集
	 *
	 * 思路：将有交集的情况列出,若不符合有交集的情况,则无交集
	 *    有交集的两种情况
	 *    1.第一个时间段的开始时间在第二个时间段的开始时间和结束时间当中
	 *    2.第二个时间段的开始时间在第一个时间段的开始时间和结束时间当中
	 *
	 * @author licancan
	 * @param leftStartDate 第一个时间段的开始时间
	 * @param leftEndDate 第一个时间段的结束时间
	 * @param rightStartDate 第二个时间段的开始时间
	 * @param rightEndDate 第二个时间段的结束时间
	 * @return {@link boolean} 若有交集, 返回true, 否则返回false
	 */
	public static boolean hasOverlap(LocalDate leftStartDate, LocalDate leftEndDate, LocalDate rightStartDate, LocalDate rightEndDate) {
		return ((leftStartDate.equals(rightStartDate) || leftStartDate.isAfter(rightStartDate))
				&& leftStartDate.isBefore(rightEndDate))
				||
				(leftStartDate.isAfter(rightStartDate)
						&& (leftStartDate.equals(rightEndDate) || leftStartDate.isBefore(rightEndDate)))
				||
				((rightStartDate.equals(leftStartDate) || rightStartDate.isAfter(leftStartDate))
						&& rightStartDate.isBefore(leftEndDate))
				||
				(rightStartDate.isAfter(leftStartDate)
						&& (rightStartDate.equals(leftEndDate) || rightStartDate.isBefore(leftEndDate)));
	}

	/*public static void main(String[] args)
		System.out.println(parseLocalDate("2022-8-3"))
	}*/

	/**
	 * 日期转字符串
	 * @author chenyuxi
	 * @param date
	 * @return {@link String}
	 */
	public static String getDateSrt(LocalDate date){
		// 格式化日期
		return getDateSrt(date,NORM_DATE_PATTERN);
	}

	/**
	 * 日期转字符串
	 * @author chenyuxi
	 * @param date
	 * @param pattern
	 * @return {@link String}
	 */
	public static String getDateSrt(LocalDate date, String pattern){
		if(Common.isEmpty(pattern)){
			pattern = NORM_DATE_PATTERN;
		}
       // 定义日期格式
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);

		// 格式化日期
		return date.format(formatter);
	}
	/**
	 * @Author fxj
	 * @Description 判断 日期policyEffect及policyEnd  与 日期policyStart及policyEnd1 是否时间上有重叠，有返回true 否返回 false
	 * @Date 14:52 2025/11/20
	 * @Param
	 * @return
	**/
	public static boolean hasOverlap(Date start1, Date end1, Date start2, Date end2) {
		// 检查参数有效性
		if (start1 == null || end1 == null || start2 == null || end2 == null) {
			return  false ;
		}
		// 检查单个时间段的开始结束时间是否合理
		if (start1.after(end1) || start2.after(end2)) {
			return false;
		}
		// 判断不重叠的情况，然后取反
		// 时间段1完全在时间段2之前，或者时间段1完全在时间段2之后
		return !(end1.before(start2) || start1.after(end2));
	}
}
