package com.aps.common.util;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
import java.util.Locale;

/**
 * 通用时间工具类
 * 覆盖：格式化/解析、类型转换、日期增减、节假日判断、时间戳转换、工作日校验等核心场景
 */
public class DateTimeUtil {

    // ======================== 常用时间格式常量 ========================
    public static final String FORMAT_YMD = "yyyy-MM-dd";
    public static final String FORMAT_YMD_HMS = "yyyy-MM-dd HH:mm:ss";
    public static final String FORMAT_YMD_HM = "yyyy-MM-dd HH:mm";
    public static final String FORMAT_HMS = "HH:mm:ss";
    public static final String FORMAT_YMD_CN = "yyyy年MM月dd日";
    // 默认时区（可根据业务调整为UTC/Asia/Shanghai等）
    public static final ZoneId DEFAULT_ZONE = ZoneId.systemDefault();

    // ======================== 格式化：时间对象 → 字符串 ========================
    /**
     * LocalDateTime 格式化为字符串
     * @param localDateTime 待格式化时间（null返回空串）
     * @param pattern       格式模板（如 FORMAT_YMD_HMS）
     */
    public static String format(LocalDateTime localDateTime, String pattern) {
        if (localDateTime == null || pattern == null) {
            return "";
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        return localDateTime.format(formatter);
    }

    /**
     * Date 格式化为字符串
     */
    public static String format(Date date, String pattern) {
        if (date == null) {
            return "";
        }
        LocalDateTime localDateTime = dateToLocalDateTime(date);
        return format(localDateTime, pattern);
    }

    /**
     * 时间戳（毫秒）格式化为字符串
     */
    public static String format(long timestamp, String pattern) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), DEFAULT_ZONE);
        return format(localDateTime, pattern);
    }

    // ======================== 解析：字符串 → 时间对象 ========================
    /**
     * 字符串解析为 LocalDateTime
     * @param dateStr 时间字符串（如 "2025-12-24 10:00:00"）
     * @param pattern 格式模板（需与字符串匹配）
     * @return 解析失败返回 null
     */
    public static LocalDateTime parseLocalDateTime(String dateStr, String pattern) {
        if (dateStr == null || pattern == null) {
            return null;
        }
        try {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            return LocalDateTime.parse(dateStr, formatter);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 字符串解析为 Date
     */
    public static Date parseDate(String dateStr, String pattern) {
        LocalDateTime localDateTime = parseLocalDateTime(dateStr, pattern);
        return localDateTime == null ? null : localDateTimeToDate(localDateTime);
    }

    // ======================== 类型转换：Date ↔ LocalDateTime ========================
    /**
     * Date 转 LocalDateTime
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        if (date == null) {
            return null;
        }
        return date.toInstant().atZone(DEFAULT_ZONE).toLocalDateTime();
    }

    /**
     * LocalDateTime 转 Date
     */
    public static Date localDateTimeToDate(LocalDateTime localDateTime) {
        if (localDateTime == null) {
            return null;
        }
        return Date.from(localDateTime.atZone(DEFAULT_ZONE).toInstant());
    }

    // ======================== 日期增减：年/月/日/时/分/秒 ========================
    /**
     * LocalDateTime 增减指定时间单位
     * @param localDateTime 基准时间
     * @param amount        增减数量（正数加，负数减）
     * @param unit          时间单位（ChronoUnit.DAYS/HOURS等）
     */
    public static LocalDateTime plus(LocalDateTime localDateTime, long amount, ChronoUnit unit) {
        if (localDateTime == null || unit == null) {
            return null;
        }
        return localDateTime.plus(amount, unit);
    }

    /**
     * Date 增减指定时间单位
     */
    public static Date plus(Date date, long amount, ChronoUnit unit) {
        LocalDateTime localDateTime = dateToLocalDateTime(date);
        LocalDateTime newLdt = plus(localDateTime, amount, unit);
        return localDateTimeToDate(newLdt);
    }

    // ======================== 常用日期获取：当天开始/结束、本月第一天/最后一天 ========================
    /**
     * 获取当天开始时间（如 2025-12-24 00:00:00）
     */
    public static LocalDateTime getStartOfDay(LocalDateTime localDateTime) {
        return localDateTime == null ? null : localDateTime.with(LocalTime.MIN);
    }

    /**
     * 获取当天结束时间（如 2025-12-24 23:59:59.999999999）
     */
    public static LocalDateTime getEndOfDay(LocalDateTime localDateTime) {
        return localDateTime == null ? null : localDateTime.with(LocalTime.MAX);
    }

    /**
     * 获取本月第一天（如 2025-12-01 00:00:00）
     */
    public static LocalDateTime getFirstDayOfMonth(LocalDateTime localDateTime) {
        if (localDateTime == null) {
            return null;
        }
        return localDateTime.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
    }

    /**
     * 获取本月最后一天（如 2025-12-31 23:59:59.999999999）
     */
    public static LocalDateTime getLastDayOfMonth(LocalDateTime localDateTime) {
        if (localDateTime == null) {
            return null;
        }
        return localDateTime.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX);
    }

    // ======================== 时间戳转换 ========================
    /**
     * LocalDateTime 转时间戳（毫秒）
     */
    public static long toTimestamp(LocalDateTime localDateTime) {
        if (localDateTime == null) {
            return 0L;
        }
        return localDateTime.atZone(DEFAULT_ZONE).toInstant().toEpochMilli();
    }

    /**
     * 时间戳（毫秒）转 LocalDateTime
     */
    public static LocalDateTime fromTimestamp(long timestamp) {
        if (timestamp <= 0) {
            return null;
        }
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), DEFAULT_ZONE);
    }

    // ======================== 工作日/节假日判断（基础版，可扩展） ========================
    /**
     * 判断是否为工作日（周一到周五）
     */
    public static boolean isWorkDay(LocalDateTime localDateTime) {
        if (localDateTime == null) {
            return false;
        }
        DayOfWeek dayOfWeek = localDateTime.getDayOfWeek();
        return dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY;
    }

    /**
     * 判断是否为周末（周六/周日）
     */
    public static boolean isWeekend(LocalDateTime localDateTime) {
        return !isWorkDay(localDateTime);
    }

    // ======================== 扩展：获取指定日期是周几（中文） ========================
    /**
     * 获取周几（如 "周一"、"周日"）
     */
    public static String getWeekName(LocalDateTime localDateTime) {
        if (localDateTime == null) {
            return "";
        }
        String[] weekNames = {"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
        DayOfWeek dayOfWeek = localDateTime.getDayOfWeek();
        return weekNames[dayOfWeek.getValue() % 7];
    }
    public static Duration diffDuration(LocalDateTime start, LocalDateTime end) {
        if (start == null || end == null) {
            return Duration.ZERO;
        }
        return Duration.between(start, end);
    }

    // ======================== 测试示例 ========================
    public  void test() {
        // 1. 格式化
        LocalDateTime now = LocalDateTime.now();
        System.out.println("当前时间（yyyy-MM-dd HH:mm:ss）：" + format(now, FORMAT_YMD_HMS));

        // 2. 解析
        String dateStr = "2025-12-24 10:30:00";
        LocalDateTime parseLdt = parseLocalDateTime(dateStr, FORMAT_YMD_HMS);
        System.out.println("解析后的时间：" + parseLdt);

        // 3. 类型转换
        Date date = localDateTimeToDate(now);
        LocalDateTime ldt = dateToLocalDateTime(date);
        System.out.println("Date转LocalDateTime：" + ldt);

        // 4. 日期增减
        LocalDateTime nextDay = plus(now, 1, ChronoUnit.DAYS);
        System.out.println("明天此时：" + format(nextDay, FORMAT_YMD_HMS));

        // 5. 当天开始/结束
        LocalDateTime startOfDay = getStartOfDay(now);
        System.out.println("当天开始时间：" + format(startOfDay, FORMAT_YMD_HMS));

        // 6. 工作日判断
        System.out.println("今天是否为工作日：" + isWorkDay(now));

        // 7. 周几
        System.out.println("今天是：" + getWeekName(now));
    }
}
