package com.yida.data.common.core.utils;

import cn.hutool.core.date.DateUnit;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

/**
 * 时间工具类
 *
 * @author MrBird
 */
public abstract class DateUtil {

    public static final String FULL_TIME_PATTERN = "yyyyMMddHHmmss";

    public static final String FULL_TIME_SPLIT_PATTERN = "yyyy-MM-dd HH:mm:ss";

    public static final String CST_TIME_PATTERN = "EEE MMM dd HH:mm:ss zzz yyyy";

    /**
     * 格式化时间，格式为 yyyyMMddHHmmss
     *
     * @param localDateTime LocalDateTime
     * @return 格式化后的字符串
     */
    public static String formatFullTime(LocalDateTime localDateTime) {
        return formatFullTime(localDateTime, FULL_TIME_PATTERN);
    }

    /**
     * 根据传入的格式，格式化时间
     *
     * @param localDateTime LocalDateTime
     * @param format        格式
     * @return 格式化后的字符串
     */
    public static String formatFullTime(LocalDateTime localDateTime, String format) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format);
        return localDateTime.format(dateTimeFormatter);
    }

    /**
     * 根据传入的格式，格式化时间
     *
     * @param date   Date
     * @param format 格式
     * @return 格式化后的字符串
     */
    public static String getDateFormat(Date date, String format) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format, Locale.CHINA);
        return simpleDateFormat.format(date);
    }

    /**
     * 格式化 CST类型的时间字符串
     *
     * @param date   CST类型的时间字符串
     * @param format 格式
     * @return 格式化后的字符串
     * @throws ParseException 异常
     */
    public static String formatCstTime(String date, String format) throws ParseException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(CST_TIME_PATTERN, Locale.US);
        Date usDate = simpleDateFormat.parse(date);
        return getDateFormat(usDate, format);
    }

    /**
     * 格式化 Instant
     *
     * @param instant Instant
     * @param format  格式
     * @return 格式化后的字符串
     */
    public static String formatInstant(Instant instant, String format) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        return localDateTime.format(DateTimeFormatter.ofPattern(format));
    }

    /**
     * 判断当前时间是否在指定时间范围
     *
     * @param from 开始时间
     * @param to   结束时间
     * @return 结果
     */
    public static boolean between(LocalTime from, LocalTime to) {
        LocalTime now = LocalTime.now();
        return now.isAfter(from) && now.isBefore(to);
    }


    /**
     * 计算两个时间点相差的天数
     *
     * @param
     * @return
     */
    public static Long daysBetween(Date beginDate, Date endDate) {
        return cn.hutool.core.date.DateUtil.between(beginDate, endDate, DateUnit.DAY);
    }


    /**
     * 获取指定年指定月的开始天数和结束天数
     *
     * @param yearMonth
     * @return
     */
    public static Map<String, Date> getFirstDayAndLastDayOfTheSpecifiedMonth(String yearMonth) {

        int year = Integer.parseInt(yearMonth.split("-")[0]);
        int month = Integer.parseInt(yearMonth.split("-")[1]);
        // 获取当前分区的日历信息(这里可以使用参数指定时区)
        Calendar calendar = Calendar.getInstance();
        // 设置年
        calendar.set(Calendar.YEAR, year);
        // 设置月，月份从0开始
        calendar.set(Calendar.MONTH, month - 1);
        // 设置为指定月的第一天
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        // 获取指定月第一天的时间
        Date start = calendar.getTime();
        // 设置日历天数为当前月实际天数的最大值，即指定月份的最后一天
        calendar.set(Calendar.DATE, calendar.getActualMaximum(Calendar.DATE));
        // 获取最后一天的时间
        Date end = calendar.getTime();
        // 设置返回信息,返回样式根据需求自行格式化
        Map<String, Date> dateMap = new HashMap<>();
        dateMap.put("start", start);
        dateMap.put("end", end);
        return dateMap;
    }


    /**
     * 查询日期间有几天一周中的某一天 日期格式 yyyy-MM-dd yyyy-MM-dd 1-7(表示周一到周日)
     *
     * @param startDate 准备查询的起始日期
     * @param endDate   准备查询的结束日期
     * @param dayOfWeek 准备查的一周中的某一天(准备查周几？)
     * @return 包含所查周几的天数
     * @throws ParseException 不支持跨年查询、不支持结束日期早于起始日期、周几输入错误等
     */
    public static Integer getMondayNumber(LocalDate startDate, LocalDate endDate, int dayOfWeek) throws ParseException {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            int differenceDay = 0;
            //实例化起始和结束Calendar对象
            Calendar startCalendar = Calendar.getInstance();
            Calendar endCalendar = Calendar.getInstance();
            //分别设置Calendar对象的时间
            ZoneId zone = ZoneId.systemDefault();
            Instant instantStartDate = startDate.atStartOfDay().atZone(zone).toInstant();
            Instant instantEndDate = endDate.atStartOfDay().atZone(zone).toInstant();
            startCalendar.setTime(Date.from(instantStartDate));
            endCalendar.setTime(Date.from(instantEndDate));

            //定义起始日期和结束日期分别属于第几周
            int startWeek = startCalendar.get(Calendar.WEEK_OF_YEAR);
            int endWeek = endCalendar.get(Calendar.WEEK_OF_YEAR);

            //拿到起始日期是星期几
            int startDayOfWeek = startCalendar.get(Calendar.DAY_OF_WEEK);
            if (startDayOfWeek == 1) {
                startDayOfWeek = 7;
                startWeek--;
            } else {
                startDayOfWeek--;
            }

            //拿到结束日期是星期几
            int endDayOfWeek = endCalendar.get(Calendar.DAY_OF_WEEK);
            if (endDayOfWeek == 1) {
                endDayOfWeek = 7;
                endWeek--;
            } else {
                endDayOfWeek--;
            }

            //计算相差的周数
            int differenceWeek = endWeek - startWeek;

            //开始计算
            if (startDayOfWeek <= dayOfWeek) {
                if (endDayOfWeek >= dayOfWeek) {
                    differenceDay = differenceWeek + 1;
                }
            } else if (startDayOfWeek > dayOfWeek) {
                if (endDayOfWeek < dayOfWeek) {
                    differenceDay = differenceWeek - 1;
                }
            } else {
                differenceDay = differenceWeek;
            }
            return differenceDay;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
