package shop.alien.util.lunar;

import com.nlf.calendar.*;
import com.nlf.calendar.util.HolidayUtil;

import java.time.LocalDate;
import java.util.*;

/**
 * 开源日期工具类
 *
 * @author ssk
 * @version 1.0
 * @date 2024/4/23 11:41
 */
public class LunarUtils {

    public static void main(String[] args) {
//        System.out.println(getFestival("2025-05-12", true));

//        isLeapYear("2024-05-01");

//        getXingZuo("2024-05-01");

//        System.out.println(getOldDate("2024-04-25"));
//        getDayYiJi("2024-04-25");
//        getJieQi("2024-04-25");
//        System.out.println(getNextHoliday("2024-01-02", 1));
//        String startDate = "2024-05-10-19-10-00";
//        String endDate = "2024-05-10-19-10-01";
//        System.out.println(isBefore(startDate, endDate));
//        List<Holiday> festivalByYear = getFestivalByYear(LocalDate.now().getYear() + "", 0);
//        for (Holiday holiday : festivalByYear) {
//            System.out.println(holiday.getDay());
//            System.out.println(holiday.getName());
//        }
//        System.out.println(getNextHoliday("2024-05-13", 0));

//        List<Holiday> holidays = HolidayUtil.getHolidays("2025");
//        System.out.println(holidays);
//
//        SolarDay solarDay = SolarDay.fromYmd(2023, 10, 1);
//        LegalHoliday holiday = solarDay.getLegalHoliday();
//        LegalHoliday legalHoliday = new LegalHoliday(2024, 11, 20,"2024-11-20");
//        LegalHoliday next = legalHoliday.next(1);
//        System.out.println(next);
//        HolidayUtil.fix("202501010120250101202501261020250129202501281120250129202501291120250129202501301120250129202501311120250129202502011120250129202502021120250129202502031120250129202502041120250129202502081020250129202504042120250404202504052120250404202504062120250404202504273020250501202505013120250501202505023120250501202505033120250501202505043120250501202505053120250501202505314120250531202506014120250531202506024120250531202509287020251001202510017120251001202510027120251001202510037120251001202510047120251001202510057120251001202510067120251001202510077120251001202510087120251001202510117020251001");
//        List<Holiday> holidays = HolidayUtil.getHolidays("2025");
//        System.out.println(holidays);
//
//
//        Map<String, Object> nextHoliday = getNextHoliday("2025-01-01", 0);
//        System.out.println(nextHoliday);
        System.out.println(getShuJiu("2024-12-31"));
    }

    public static Map<String, Object> getDateInfo(String date) {
        Map<String, Object> resultMap = new HashMap<>();
        Solar solar = setSolarDateFromYmd(date);
        resultMap.put("week", solar.getWeek());
        resultMap.put("week_zh", solar.getWeekInChinese());
        return resultMap;
    }

    /**
     * 时间比较
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return boolean
     */
    public static boolean isBefore(String startDate, String endDate) {
        Solar start = setDateFromYmdHms(startDate);
        Solar end = setDateFromYmdHms(endDate);
        return start.isBefore(end);
    }

    /**
     * 是否闰年
     *
     * @param date 日期
     * @return boolean
     */
    public static boolean isLeapYear(String date) {
        Solar solar = setSolarDateFromYmd(date);
        return solar.isLeapYear();
    }

    /**
     * 获取节日
     *
     * @param date           查询日期(yyyy-mm-dd)
     * @param otherFestivals (true:普通节日, false:其他纪念日)
     * @return List<String>
     */
    public static List<String> getFestival(String date, boolean otherFestivals) {
        Solar solar = setSolarDateFromYmd(date);
        List<String> resultList;
        if (otherFestivals) {
            //返回节日的数组，包括元旦节、国庆节等，也包括母亲节、父亲节、感恩节、圣诞节等，有可能同一天有多个，也可能没有。
            resultList = solar.getFestivals();
        } else {
            //返回其他纪念日的数组，例如世界抗癌日、香港回归纪念日等，有可能同一天有多个，也可能没有。
            resultList = solar.getOtherFestivals();
        }
        return resultList;
    }

    /**
     * 获取星座
     *
     * @param date 查询日期
     * @return String
     */
    public static String getXingZuo(String date) {
        Solar solar = setSolarDateFromYmd(date);
        return solar.getXingZuo();
    }

    /**
     * 获取农历日期信息
     *
     * @param date 阳历日期
     * @return map
     */
    public static Map<String, Object> getOldDate(String date) {
        Map<String, Object> resultMap = new HashMap<>();
        Solar solar = setSolarDateFromYmd(date);
        Lunar lunar = solar.getLunar();
        String[] lunarStr = lunar.toFullString().split(" ");
        resultMap.put("old_date", lunarStr[0].substring(5));
        resultMap.put("old_year", lunarStr[1]);
        return resultMap;
    }

    /**
     * 获取每日宜忌
     *
     * @param date 阳历日期
     * @return map
     */
    public static Map<String, Object> getDayYiJi(String date) {
        Map<String, Object> resultMap = new HashMap<>();
        Solar solar = setSolarDateFromYmd(date);
        Lunar lunar = solar.getLunar();
        List<String> dayYi = lunar.getDayYi();
        resultMap.put("day_yi", dayYi.toString().substring(1, dayYi.toString().length() - 1));
        List<String> dayJi = lunar.getDayJi();
        resultMap.put("day_ji", dayJi.toString().substring(1, dayJi.toString().length() - 1));
        return resultMap;
    }

    /**
     * 根据日期获取最近节气
     *
     * @param date 日期
     * @return map
     */
    public static Map<String, Object> getJieQi(String date) {
        Map<String, Object> resultMap = new HashMap<>();
        Solar solar = setSolarDateFromYmd(date);
        Lunar lunar = solar.getLunar();
        JieQi currentJieQi = lunar.getCurrentJieQi();
        if (currentJieQi != null) {
            resultMap.put("name", currentJieQi.getName());
            resultMap.put("day", 0);
        } else {
            JieQi nextJieQi = lunar.getNextJieQi();
            resultMap.put("name", nextJieQi.getName());
            resultMap.put("day", subtractDate(date, nextJieQi.getSolar().toString()));
        }
        return resultMap;
    }

    /**
     * 获取下一个节日
     *
     * @param date            日期yyyy-MM-dd
     * @param allFestivalFlag 所有节日标记{0:全部,1:传统节日,2:其他节日,99:不显示节日}
     * @return map
     */
    public static Map<String, Object> getNextHoliday(String date, Integer allFestivalFlag) {
        int count = 0;
        Map<String, Object> resultMap = new HashMap<>();
        //今年所有节假日
        List<Holiday> all = HolidayUtil.getHolidays(Integer.parseInt(date.substring(0, 4)));
        if (allFestivalFlag != 99) {
            List<Holiday> festivals = getFestivalByYear(date.substring(0, 4), allFestivalFlag);
            //是否重复
            for (Holiday festival : festivals) {
                boolean flag = false;
                for (Holiday holiday : all) {
                    if (holiday.getDay().equals(festival.getDay())) {
                        String newName = holiday.getName() + "," + festival.getName();
                        List<String> listContains = listContains(Arrays.asList(newName.split(",")));
                        String name = "";
                        for (String s : listContains) {
                            name = s + ",";
                        }
                        holiday.setName(name.substring(0, name.length() - 1));
                        flag = true;
                        break;
                    }
                }
                //不重复的话
                if (!flag) {
                    all.add(festival);
                }
            }
        }
        //升序
        all.sort(Comparator.comparing(Holiday::getDay).thenComparing(Holiday::getDay));
        for (Holiday holiday : all) {
            count++;
            Solar startDate = setSolarDateFromYmd(date);
            Solar endDate = setSolarDateFromYmd(holiday.getDay());
            //排除已过的节日
            if (date.equals(holiday.getDay()) || startDate.isBefore(endDate)) {
                resultMap.put("work", holiday.isWork());
                if (holiday.isWork()) {
                    resultMap.put("name", holiday.getName() + "调休工作日");
                } else {
                    resultMap.put("name", holiday.getName());
                }
                int subtractDate = subtractDate(LocalDate.now().toString(), holiday.getDay());
                resultMap.put("subtract_date", subtractDate);
                resultMap.put("day", holiday.getDay());
                return resultMap;
            } else {
                if (count == all.size()) {
                    //今年的循环完毕, 获取明年的
                    int nextYear = Integer.parseInt(date.substring(0, 4)) + 1;
                    return getNextHoliday(nextYear + "-01-01", allFestivalFlag);
                }
            }
        }
        return resultMap;
    }

    /**
     * 获取两个日期相差天数
     *
     * @param startDate 小日期
     * @param endDate   大日期
     * @return int
     */
    public static int subtractDate(String startDate, String endDate) {
        Solar startSolar = setSolarDateFromYmd(startDate);
        Solar endSolar = setSolarDateFromYmd(endDate);
        return endSolar.subtract(startSolar);
    }

    /**
     * 设置阳历查询日期
     *
     * @param date 日期yyyymmdd
     * @return Solar
     */
    private static Solar setSolarDateFromYmd(String date) {
        String[] dateSplit = date.split("-");
        return Solar.fromYmd(Integer.parseInt(dateSplit[0]), Integer.parseInt(dateSplit[1]), Integer.parseInt(dateSplit[2]));
    }

    /**
     * 设置阴历查询日期
     *
     * @param date 日期yyyymmdd
     * @return Solar
     */
    private static Lunar setLunarDateFromYmd(String date) {
        Solar solar = setSolarDateFromYmd(date);
        return solar.getLunar();
    }

    /**
     * 设置查询日期yyyymmddhhmmss
     *
     * @param date 日期
     * @return Solar
     */
    private static Solar setDateFromYmdHms(String date) {
        String[] dateSplit = date.split("-");
        return Solar.fromYmdHms(Integer.parseInt(dateSplit[0]), Integer.parseInt(dateSplit[1]), Integer.parseInt(dateSplit[2]), Integer.parseInt(dateSplit[3]), Integer.parseInt(dateSplit[4]), Integer.parseInt(dateSplit[5]));
    }

    /**
     * 根据年份获取节日
     *
     * @param year            年份
     * @param allFestivalFlag 所有节日标记{0:全部,1:传统节假期,2:其他节假日}
     */
    public static List<Holiday> getFestivalByYear(String year, Integer allFestivalFlag) {
        List<Holiday> holidays = new ArrayList<>();
        //闰年
        boolean leapYear = isLeapYear(year + "-01-01");
        List<Integer> monthHasDays;
        if (leapYear) {
            monthHasDays = Arrays.asList(31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
        } else {
            monthHasDays = Arrays.asList(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
        }
        for (int i = 0; i < monthHasDays.size(); i++) {
            int month = i + 1;
            String monthStr = month > 9 ? "" + month : "0" + month;
            for (int i1 = 0; i1 < monthHasDays.get(i); i1++) {
                int day = i1 + 1;
                String dayStr = day > 9 ? "" + day : "0" + day;
                String yyyyMMdd = year + "-" + monthStr + "-" + dayStr;
                List<String> festival = new ArrayList<>();
                if (allFestivalFlag == 1 || allFestivalFlag == 0) {
                    festival.addAll(getFestival(yyyyMMdd, true));
                }
                if (allFestivalFlag == 2 || allFestivalFlag == 0) {
                    festival.addAll(getFestival(yyyyMMdd, false));
                }
                StringBuilder name = new StringBuilder();
                for (String s : festival) {
                    name.append(s).append(",");
                }
                String sb = name.toString();
                if (!sb.isEmpty()) {
                    Holiday holiday = new Holiday();
                    holiday.setDay(yyyyMMdd);
                    holiday.setName(sb.substring(0, sb.length() - 1));
                    Holiday dayInfo = HolidayUtil.getHoliday(Integer.parseInt(yyyyMMdd.substring(0, 4)), Integer.parseInt(yyyyMMdd.substring(5, 7)), Integer.parseInt(yyyyMMdd.substring(8, 10)));
                    if (dayInfo != null) {
                        holiday.setWork(dayInfo.isWork());
                    } else {
                        holiday.setWork(false);
                    }
                    holidays.add(holiday);
                }
            }
        }
        return holidays;
    }

    /**
     * 数九
     *
     * @param date 查询日期
     * @return 结果
     */
    public static String getShuJiu(String date) {
        Lunar lunar = setLunarDateFromYmd(date);
        ShuJiu shuJiu = lunar.getShuJiu();
        if (null != shuJiu) {
            return shuJiu.toFullString();
        }
        return "";
    }

    /**
     * 自定义去重
     *
     * @param list 去重集合
     */
    public static List<String> listContains(List<String> list) {
        //新集合
        List<String> newList = new ArrayList<>();
        list.forEach(i -> {
            if (!newList.contains(i)) {//如果新集合中不存在则插入
                newList.add(i);
            }
        });
        return newList;
    }

}
