package com.cf.imes.framework.common.util.time;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import com.cf.imes.framework.common.enums.StatisticsUnit;
import com.cf.imes.framework.common.pojo.CommonStatisticsReqVO;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.List;

/**
 * 统计时间转换工具类
 */
public class StatisticsChangeUtils {

    /**
     * 获取日期区间格式下的所有日期字符串
     * 1、reqVO设置机构id
     * 2、计算时间跨度设置到reqVO
     * 3、返回所有日期的集合
     * @return
     */
    public static List<String> getDateList(CommonStatisticsReqVO reqVO) {
        // 计算时间跨度
        getTimeSpan(reqVO);

        // 重新计算开始时间和结束时间
        computeTimeSpan(reqVO);

        // 所有的日期集合
        return generateDateRange(reqVO);
    }

    /**
     * 获取统计的时间跨度
     * 计算起止时间：前端不传入时间就根据维度单位从当前日期计算
     *
     */
    public static void getTimeSpan(CommonStatisticsReqVO reqVO) {
        LocalDate[] createTime = reqVO.getCreateTime();
        LocalDate startTime = null;
        LocalDate endTime;
        LocalDate now = LocalDate.now();
        if (ArrayUtil.isEmpty(createTime) || ObjectUtil.isNull(createTime[0]) || ObjectUtil.isNull(createTime[1])) {
            endTime = now;
            switch (StatisticsUnit.fromValue(reqVO.getUnit())) {
                case QUARTER:
                    // 从now往前的2年
                    startTime = now.minusYears(1);
                    break;
                case MONTH:
                    // 包含now往前的12个月
                    startTime = now.minusMonths(11);
                    break;
                case WEEK:
                    // 包含now往前的12周
                    startTime = now.minusWeeks(11);
                    break;
                case DAY:
                    // 包含now往前的15天
                    startTime = now.minusDays(14);
                    break;
                default:
                    break;
            }
            // 声明一个LocalDateTime的数组，把startTime和endTime放进去
            reqVO.setCreateTime(new LocalDate[]{startTime, endTime});
        }
    }

    /**
     * 根据传入信息重新计算时间范围
     *
     * @param reqVO
     */
    public static void computeTimeSpan(CommonStatisticsReqVO reqVO) {
        Integer unit = reqVO.getUnit();
        // 计算后的开始和结束时间
        LocalDate startDate = ObjectUtil.clone(reqVO.getCreateTime()[0]);
        LocalDate endDate = ObjectUtil.clone(reqVO.getCreateTime()[1]);

        if (startDate.isAfter(endDate)) {
            startDate = ObjectUtil.clone(reqVO.getCreateTime()[1]);
            endDate = ObjectUtil.clone(reqVO.getCreateTime()[0]);
        }
        LocalDate first;
        LocalDate end;
        switch (StatisticsUnit.fromValue(unit)) {
            case QUARTER -> {
                first = firstDayOfQuarter(startDate);
                end = lastDayOfQuarter(endDate);
            }
            case MONTH -> {
                first = startDate.with(TemporalAdjusters.firstDayOfMonth());
                end = endDate.with(TemporalAdjusters.lastDayOfMonth());
            }
            case WEEK -> {
                first = startDate.with(TemporalAdjusters.previousOrSame(java.time.DayOfWeek.MONDAY));
                end = endDate.with(TemporalAdjusters.nextOrSame(java.time.DayOfWeek.SUNDAY));
            }
            default -> {
                return;
            }
        }
        reqVO.setCreateTime(new LocalDate[]{first, end});
    }

    /**
     * 获取日期范围内的所有格式字符串
     *
     * @return
     */
    public static List<String> generateDateRange(CommonStatisticsReqVO reqVO) {
        Integer unit = reqVO.getUnit();
        // 计算时间跨度
        getTimeSpan(reqVO);
        // 计算后的开始和结束时间
        LocalDate startDate = ObjectUtil.clone(reqVO.getCreateTime()[0]);
        LocalDate endDate = ObjectUtil.clone(reqVO.getCreateTime()[1]);

        List<String> dates = new ArrayList<>();
        while (!startDate.isAfter(endDate)) {
            String dateStr;
            switch (StatisticsUnit.fromValue(unit)) {
                case QUARTER:
                    dateStr = startDate.format(DateTimeFormatter.ofPattern("yyyy-Q"));
                    // 加一季度（3个月）
                    startDate = startDate.plusMonths(3);
                    break;
                case MONTH:
                    dateStr = startDate.format(DateTimeFormatter.ofPattern("yyyy-M"));
                    // 加一月
                    startDate = startDate.plusMonths(1);
                    break;
                case WEEK:
                    // 使用自定义格式表示月份
                    dateStr = startDate.format(DateTimeFormatter.ofPattern("yyyy-M"));
                    // 计算从月份第一天到当前日期经过了多少周
                    LocalDate monthStart = startDate.with(TemporalAdjusters.firstDayOfMonth());
                    long weeksInMonth = ChronoUnit.WEEKS.between(monthStart, startDate) + 1;
                    dateStr = dateStr + "-" + weeksInMonth;
                    // 加一周
                    startDate = startDate.plusWeeks(1);
                    break;
                case DAY:
                    dateStr = startDate.format(DateTimeFormatter.ofPattern("yyyy-M-d"));
                    // 加一天
                    startDate = startDate.plusDays(1);
                    break;
                default:
                    throw new IllegalArgumentException("Unsupported unit: " + unit);
            }
            dates.add(dateStr);
        }
        return dates;
    }

    /**
     * 构建日期格式到图标横轴可用格式
     * 2024-1 -> 2024年第1季度
     * 2024-1-1 -> 2024年1月
     * ...
     * @param unit
     * @return
     */
    public static String generateDateRangeAxis(String date, Integer unit) {
        StatisticsUnit statisticsUnit = StatisticsUnit.fromValue(unit);
        StringBuilder newDateStrBuffer = new StringBuilder();
        String[] dateSplit = date.split("-");
        switch (statisticsUnit) {
            case QUARTER:
                newDateStrBuffer.append("第").append(dateSplit[1]).append("季度");
                break;
            case MONTH:
                newDateStrBuffer.append(dateSplit[1]).append("月");
                break;
            case WEEK:
                newDateStrBuffer.append("第").append(dateSplit[2]).append("周");
                break;
            case DAY:
                newDateStrBuffer.append(dateSplit[2]);
                break;
            default:
        }
        return newDateStrBuffer.toString();
    }

    /**
     * 获取指定日期所在季度的开始日期
     *
     * @param date
     * @return
     */
    private static LocalDate firstDayOfQuarter(LocalDate date) {
        int month = date.getMonthValue();
        int quarter = (month - 1) / 3 + 1;
        int startMonth = (quarter - 1) * 3 + 1;
        return LocalDate.of(date.getYear(), startMonth, 1);
    }

    /**
     * 获取指定日期所在季度的结束日期
     *
     * @param date
     * @return
     */
    private static LocalDate lastDayOfQuarter(LocalDate date) {
        int month = date.getMonthValue();
        int quarter = (month - 1) / 3 + 1;
        int endMonth = (quarter - 1) * 3 + 3;
        return LocalDate.of(date.getYear(), endMonth, 1).with(TemporalAdjusters.lastDayOfMonth());
    }
}
