package com.storlead.framework.common.util;

import lombok.extern.slf4j.Slf4j;

import java.time.*;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;

import static java.time.ZoneId.SHORT_IDS;
/**
 * @program: sp-sales
 * @description: jdk8日期判断工具类
 * @author: xiaojiawei
 * @create: 2022-01-18 09:57
 **/
@Slf4j
public class LocalDateUtils {


    public static Date LocalDate2Date(LocalDate date){
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = date.atStartOfDay().atZone(zone).toInstant();
        Date da = Date.from(instant);
        return da;
    }
    public static LocalDate date2LocalDate(Date date){
        Instant instant =date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        LocalDate localDate= localDateTime.toLocalDate();
        return localDate;
    }
    public static LocalDateTime date2LocalDateTime(Date date){
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();

        LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();
        return localDateTime;
    }

    public static Date localDateTime2date(LocalDateTime localDateTime){
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }
    /**
     * 从时间戳转换成 LocalDateTime
     * @param timestamp
     * @return
     */
    private static LocalDateTime timestamp(Long timestamp){
        Date date = new Date(timestamp);
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.of(SHORT_IDS.get("CTT")));
    }

    public static boolean isBetween(LocalDate date ,LocalDate t1,LocalDate t2){
        if(t1.isAfter(t2)){
            LocalDate tmp = t1;
            t1=t2;
            t2=tmp;
        }
        if(date.isBefore(t1)){
            return false;
        }
        if(date.isAfter(t2)){
            return false;
        }
        return true;
    }
    /**
     * @Description: 计算两个日期相隔的几周 ，e.g 本周日和下周一 相隔一周
     * @Param: [t1, t2]
     * @return: long  相隔几周
     * @Author: xiaojiawei
     * @Date: 2022/1/18
     */
    public static long interWeeks(LocalDate t1, LocalDate t2){
        if(t1.isAfter(t2)){
            LocalDate tmp = t1;
            t1=t2;
            t2=tmp;
        }
        t1 = t1.with(ChronoField.DAY_OF_WEEK, DayOfWeek.MONDAY.getValue());
        long weeks =  ChronoUnit.WEEKS.between(t1,t2);
        return weeks;
    }
    /**
     * 以second为主进行判断
     * 以first为开始时间，second为结束时间
     * 判断两个时间是否在通过一个周内。
     *
     * @param first
     * @param second
     */
    private static Boolean checkWeekBetween(LocalDateTime first, LocalDateTime second){
        //两个时间差不超过7天,
        Period period = Period.between(first.toLocalDate(),second.toLocalDate());
        int years = period.getYears();
        log.info("years:{}",years);
        if(years > 0){
            return false;
        }
        int months = period.getMonths();
        log.info("months:{}",months);
        if(months > 0){
            return false;
        }
        int days = period.getDays();
        log.info("days:{}",days);
        if(days == 0){
//          表明是同一天
            return true;
        }
        if(days > 7  || days < -7){
//            两个时间差 超出了7天
            return false;
        }
        int firstDayOfWeek = first.getDayOfWeek().getValue();
        int secondDayOfWeek = second.getDayOfWeek().getValue();
        if(secondDayOfWeek == 1){
            if(oneDay(firstDayOfWeek,secondDayOfWeek,days)){
                return true;
            }else {
                return false;
            }
        }
        if(secondDayOfWeek == 7){
            if(sevenDay(firstDayOfWeek,secondDayOfWeek,days)){
                return true;
            }else {
                return false;
            }
        }
        if(otherDay(firstDayOfWeek,secondDayOfWeek,days)){
            return true;
        }else{
            return false;
        }
    }

    /**
     * secondDayOfWeek 是所在星期的第一天
     * 星期的第一天 数据处理
     * @return
     */
    private static Boolean oneDay(int firstDayOfWeek,int secondDayOfWeek,int days){
        if(days > 0 ){
            // 表明 first 比second 小 不在同一周
            return false;
        }else {
            //  表明 first 比second 大
            if(secondDayOfWeek - days == firstDayOfWeek){
                return true;
            }
        }
        return false;
    }

    /**
     * 星期的第7天的时候处理数据
     * @return
     */
    private static Boolean sevenDay(int firstDayOfWeek,int secondDayOfWeek,int days){
//        second 是周日
        if(firstDayOfWeek + days == secondDayOfWeek){
            return true;
        }
        return false;
    }

    /**
     * 其他天的数据处理
     * @return
     */
    private static Boolean otherDay(int firstDayOfWeek,int secondDayOfWeek,int days){
        if(days < 0){
            //表明 first 比 second 大
            if((secondDayOfWeek - days) == firstDayOfWeek){
                //两者是 一周内
                return true;
            }
        }else {
            //表明 first 比 second 小
            if(firstDayOfWeek + days == secondDayOfWeek){
                //两者是 一周内
                return true;
            }
        }
        return false;
    }

    /**
     * 获取几月份的第几周 [X月份第X周]
     *
     * @param sourceTime 这个推荐取00:00:00时间
     * @return
     */
    public static Map<String, Object> getMonthNoAndWeekNo(LocalDateTime sourceTime) {
        Map<String, Object> map = new HashMap<>();
        String monthNoAndWeekNo = null;
        //获取当月的第一天
        LocalDateTime firstDayOfMonth = getFirstLocalDayOfMonth(sourceTime);

        //获取月第一天开始的周一,从当月第一天开始找
        LocalDateTime firstMondayOfMonth = firstDayOfMonth;
        for (int i = 0; i < 6; i++) {
            DayOfWeek dayOfWeekTemp = firstMondayOfMonth.getDayOfWeek();
            if (dayOfWeekTemp.equals(DayOfWeek.MONDAY)) {
                break;
            }
            //往后推一天
            firstMondayOfMonth = firstMondayOfMonth.plusDays(1);
        }

        //比较当月的第一个星期一 < = 参数时间
        if (!firstMondayOfMonth.isBefore(sourceTime)) {
            //如果当月的第一个周一大于参数时间,则要计算到上个月份去
            //获取上一个月的第一个周一
            LocalDateTime lastMontLocalDateTime = sourceTime.minusMonths(1);
            //上个月的第一天
            LocalDateTime firstDayOfMonth_last = getFirstLocalDayOfMonth(lastMontLocalDateTime);
            //从上个月的第一天开始找周一
            LocalDateTime firstMondayOfMonth_last = firstDayOfMonth_last;
            for (int i = 0; i < 6; i++) {
                DayOfWeek dayOfWeekTemp = firstMondayOfMonth_last.getDayOfWeek();
                if (dayOfWeekTemp.equals(DayOfWeek.MONDAY)) {
                    break;
                }
                //往后推一天
                firstMondayOfMonth_last = firstMondayOfMonth_last.plusDays(1);
            }

            //  计算两个时间间隔天数 (上月第一个周一 减去 当前时间)
            Duration duration = Duration.between(firstMondayOfMonth_last, sourceTime);
            long diffDays = duration.toDays(); //相差的天数
            //第几周weekNo
            long weekNo = (diffDays / 7) + 1;
            //月份
            int monthNo = firstMondayOfMonth_last.getMonth().getValue();//汉字版月份
            String monthChinese = getMonthChinese(monthNo);
            monthNoAndWeekNo = monthChinese + "月份" + "第" + weekNo + "周";
            map.put("yearNo",firstMondayOfMonth_last.getYear());
            map.put("monthNo", monthNo);
            map.put("weekNo", weekNo);
            map.put("monthNoAndWeekNo", monthNoAndWeekNo);

        } else {
            //当月第一个周一在当前时间之前 firstMondayOfMonth<=sourceTime
            //计算两个时间间隔天数
            int dayOfMonthFirstMonday = firstMondayOfMonth.getDayOfMonth();
            int dayOfMonthSourceTime = sourceTime.getDayOfMonth();

            int diffDays = dayOfMonthSourceTime - dayOfMonthFirstMonday;
            //第几周weekNo
            int weekNo = (diffDays / 7) + 1;
            //月份
            int monthNo = sourceTime.getMonth().getValue();
            map.put("yearNo",sourceTime.getYear());
            map.put("monthNo", monthNo);
            map.put("weekNo", weekNo);
            //汉字版月份
            String monthChinese = getMonthChinese(monthNo);
            monthNoAndWeekNo = monthChinese + "月份" + "第" + weekNo + "周";
            map.put("monthNoAndWeekNo", monthNoAndWeekNo);
        }

        return map;
    }
    /**
     * 获取汉字版月份
     *
     * @param monthNo 第几月
     * @return
     */
    private static String getMonthChinese(int monthNo) {
        switch (monthNo) {
            case 1:
                return "一";
            case 2:
                return "二";
            case 3:
                return "三";
            case 4:
                return "四";
            case 5:
                return "五";
            case 6:
                return "六";
            case 7:
                return "七";
            case 8:
                return "八";
            case 9:
                return "九";
            case 10:
                return "十";
            case 11:
                return "十一";
            case 12:
                return "十二";
            default:
                break;
        }
        return null;
    }
    /**
     * 获取某月第一天的00:00:00
     *
     * @return
     */
    public static LocalDateTime getFirstLocalDayOfMonth(LocalDateTime localDateTime) {
        return localDateTime.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
    }

    public static Date LocalDateTimeTodate(LocalDateTime localDateTime) {
        Date date = Date.from( localDateTime.atZone( ZoneId.systemDefault()).toInstant());
        return date;
    }
    /**
     * 获取当前日期所在季度的开始日期和结束日期
     * 季度一年四季， 第一季度：1月-3月， 第二季度：4月-6月， 第三季度：7月-9月， 第四季度：10月-12月
     * @param isFirst  true表示查询本季度开始日期  false表示查询本季度结束日期
     * @return
     */
    public static LocalDate getStartOrEndDayOfQuarter(Boolean isFirst){
        LocalDate today=LocalDate.now();
        LocalDate resDate = LocalDate.now();
        if (today == null) {
            today = resDate;
        }
        Month month = today.getMonth();
        Month firstMonthOfQuarter = month.firstMonthOfQuarter();
        Month endMonthOfQuarter = Month.of(firstMonthOfQuarter.getValue() + 2);
        if (isFirst) {
            resDate = LocalDate.of(today.getYear(), firstMonthOfQuarter, 1);
        } else {
            resDate = LocalDate.of(today.getYear(), endMonthOfQuarter, endMonthOfQuarter.length(today.isLeapYear()));
        }
        return resDate;
    }
    /**
     * @Description: 获取当前季度，根据月转换到季度
     * @Param:
     * @return:
     * @Author: YPZ
     * @Date: 2022-6-30
     */
    public static int getQuarterOfYear() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        return calendar.get(Calendar.MONTH) / 3 + 1;
    }

    /**
     * @Description: 获取时间对应季度
     * @Param:
     * @return:
     * @Author: YPZ
     * @Date: 2022-6-30
     */
    public static int getQuarter(LocalDateTime localDateTime) {
        return (localDateTime.getMonthValue()-1)/3 + 1;
    }
    /**
     * @Description: 根据季度获取第一天/最后一天，从季度到第一个月，再到月的第一天
     * @Param: year,quarter,isFirst(true表示查询本季度开始日期  false表示查询本季度结束日期)
     * @return:
     * @Author: YPZ
     * @Date: 2022-6-30
     */
    public static LocalDate getStartDayOfQuarter(int year, int quarter,Boolean isFirst) {

        int startMonth = (quarter - 1) * 3;

        int lastMonth = quarter * 3 - 1;

        // 根据月获取开始时间
        Calendar cal = Calendar.getInstance();

        cal.set(Calendar.YEAR, year);
        if(isFirst) {
            cal.set(Calendar.MONTH, startMonth);
            cal.set(Calendar.DAY_OF_MONTH, 1);
        }else {
            cal.set(Calendar.MONTH, lastMonth);
            cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        }

        cal.set(Calendar.HOUR, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);

        return cal.getTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    }

     /***
      * @Description: 获取两个localDate间的所有日期（从小到大排序）
      * @Param:
      * @return:
      * @Author: YPZ
      * @Date: 2022/9/7 17:55
      */
    public static  List<LocalDate> getAscDateList(LocalDate startDate,LocalDate endDate) {
        List<LocalDate> result = new ArrayList<>();
        if(endDate.compareTo(startDate) < 0 ){
            return  result;
        }
        while (true){
            result.add(startDate);
            if(startDate.compareTo(endDate) >= 0){
                break;
            }
            startDate = startDate.plusDays(1);
        }
        return result;
    }
    /***
      * @Description: java获取两个LocalDate时间段内，每隔固定天数的所有日期
      * @Param:
      * @return:
      * @Author: YPZ
      * @Date: 2023/9/19 11:26
      */
    public static List<LocalDate> getEveryOtherDayBetweenDates(LocalDate startDate, LocalDate endDate,Integer days) {
        List<LocalDate> result = new ArrayList<>();
        days = days +1;
        for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(days)) {
            result.add(date);
        }
        return result;
    }

    // 静态方法，用于计算日期范围内的每隔两周的周一和周日
    public static List<LocalDate> getMondaysAndSundays(LocalDate startDate, LocalDate endDate,int weeks) {
        weeks = weeks+1;
        List<LocalDate> result = new ArrayList<>();

        // 初始日期调整到当前周的周一
        startDate = startDate.with(DayOfWeek.MONDAY);

        // 如果第一周的周一小于开始日期，将开始日期添加到结果列表
        if (!startDate.isBefore(startDate)) {

            result.add(startDate);
        }

        // 计算两周的时间间隔
        long daysBetween = ChronoUnit.DAYS.between(startDate, endDate);

        // 计算每隔两周的日期
        for (long i = weeks*7; i <= daysBetween; i += weeks*7) {
            LocalDate monday = startDate.plusDays(i);
            result.add(monday);
        }

        return result;
    }


    public static void main(String[] args) {
//        System.out.println(getStartOrEndDayOfQuarter(false));
//        //获取当前年份
//        Calendar calendar = Calendar.getInstance();
//        int year = calendar.get(Calendar.YEAR);
//        // 获取当前季度
//        int month = calendar.get(Calendar.MONTH);
//        int quarter = month%3==0?month/3:month/3+1;
//        System.out.println(year);
//        System.out.println(quarter);
//        System.out.println(getStartDayOfQuarter(2021, 3, true));
//        System.out.println(getStartDayOfQuarter(2021, 3, false));
//
//        LocalDateTime start = LocalDateTime.now();
//        int year = start.getYear();
//        int quarter = getQuarter(start);
//
//
//        System.out.println("年度为："+year);
//        System.out.println("季度为："+quarter);
//        String dateStr = "2022-08-29";
//
//        LocalDate localDate = LocalDate.parse(dateStr , DateTimeFormatter.ofPattern("yyyy-MM-dd"));
//
//        if(localDate.equals(localDate.with(TemporalAdjusters.lastDayOfMonth()))){
//            System.out.println("是月底");
//        }
//        if(localDate.equals(localDate.with(DayOfWeek.SUNDAY))){
//            System.out.println("是周日");
//        }
//
//        String beginDateStr = "2022-08-29";
//        LocalDate beginDate = LocalDate.parse(beginDateStr , DateTimeFormatter.ofPattern("yyyy-MM-dd"));
//        String endDateStr = "2022-09-09";
//        LocalDate endDate = LocalDate.parse(endDateStr , DateTimeFormatter.ofPattern("yyyy-MM-dd"));
//        List<LocalDate> localDateList = getAscDateList(beginDate,endDate);
//        localDateList.forEach(d->System.out.println(d));

//        LocalDate startDate = LocalDate.of(2022, 1, 1);
//        LocalDate endDate = LocalDate.of(2022, 1, 10);
//        List<LocalDate> result = getEveryOtherDayBetweenDates(startDate, endDate,1);
//        for (LocalDate date : result) {
//            System.out.println(date);
//        }

//        LocalDate startDate = LocalDate.of(2023, 9, 16);
//        LocalDate endDate = LocalDate.of(2023, 12, 30);
//
//        List<LocalDate> dateRanges = getMondaysAndSundays(startDate, endDate,2);
//
//        for (LocalDate vo : dateRanges) {
//            System.out.println("Start Date: " + vo);
//        }

        LocalDate startDate = LocalDate.of(2023, 1, 2);
        LocalDate endDate = LocalDate.of(2028, 11, 26);

        for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusYears(2)) {
            LocalDate firstDayOfMonth = date.withDayOfYear(1);
            LocalDate lastDayOfMonth = date.withDayOfYear(date.lengthOfYear());
            System.out.println("月份开始时间：" + firstDayOfMonth);
            System.out.println("月份结束时间：" + lastDayOfMonth);
            System.out.println();
        }




    }
}
