package com.crm.rely.backend.util;

import com.crm.rely.backend.core.entity.base.DateIntervalEntity;
import com.google.common.collect.Lists;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;


public class DateUtil {


    public static final String DATE_FORMAT = "yyyy-MM-dd";

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

    public static final String DATE_TIME_FORMAT = "yyyyMMddHHmmss";

    public static Date orientTime;

    static {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_FORMAT);
        try {
            orientTime = simpleDateFormat.parse("1970-01-01");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 格式转化为dateTime-yyyyMMddHHmmss
     *
     * @return
     */
    public static String formatDateTime() {
        return formatDateTime(new Date());
    }

    /**
     * 格式转化为dateTime-yyyyMMddHHmmss
     *
     * @param date 时间
     * @return
     */
    public static String formatDateTime(Date date) {
        return format(DATE_TIME_FORMAT, date);
    }

    public static String formatDateTime(String orient) {
        Date date = parseTime(orient);
        return format(DATE_TIME_FORMAT, date);
    }

    /**
     * 格式转化-yyyy-MM-dd
     *
     * @return
     */
    public static String formatDate() {
        return formatDate(new Date());
    }

    /**
     * 格式转化-yyyy-MM-dd
     *
     * @param date 时间
     * @return
     */
    public static String formatDate(Date date) {
        return format(DATE_FORMAT, date);
    }

    /**
     * 格式转化-yyyy-MM-dd HH:mm:ss
     *
     * @return
     */
    public static String formatTime() {

        return formatTime(new Date());
    }

    /**
     * 格式转化-yyyy-MM-dd HH:mm:ss
     *
     * @param date
     * @return
     */
    public static String formatTime(Date date) {
        return format(TIME_FORMAT, date);
    }

    /**
     * 格式转化
     *
     * @param format 时间格式
     * @return
     */
    public static String format(String format) {
        return format(format, new Date());
    }

    /**
     * 格式转化
     *
     * @param format 时间格式
     * @param date   时间
     * @return
     */
    public static String format(String format, Date date) {
        if (date == null) {
            return "";
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(date);
    }

    public static Date parseDate() {
        return parseDate(new Date());
    }

    public static Date parseDate(String orient) {
        return parse(DATE_FORMAT, orient);
    }

    public static Date parseDate(Date date) {

        return new Date(date.getYear(), date.getMonth(), date.getDate());
    }

    public static Date parseDate(Date date, int num) {
        date = DateUtil.operationDay(date, num);
        return new Date(date.getYear(), date.getMonth(), date.getDate());
    }

    public static Date parseMonth() {
        return parseMonth(new Date());
    }

    public static Date parseMonth(Date date) {

        return new Date(date.getYear(), date.getMonth(), 1);
    }

    public static Date parseMonth(Date date, int num) {
        date = DateUtil.operationMoth(date, num);
        return new Date(date.getYear(), date.getMonth(), 1);
    }

    public static Date parseTime(String orient) {
        return parse(TIME_FORMAT, orient);
    }

    public static Date parse(String pattern, String orient) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        Date date = null;
        try {
            date = sdf.parse(orient);
        } catch (Exception e) {
            return null;
        }
        return date;
    }

    public static Date parseSearchDate(String orient, int interval) {
        SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
        if (orient.equals("") || orient == null) {
            return null;
        }
        Date date = null;
        try {
            date = sdf.parse(orient);
        } catch (Exception e) {
            date = new Date();
        }

        date = operationDay(date, interval);
        return date;
    }


    public static Date operationYear(int num) {
        return operationDate(new Date(), Calendar.YEAR, num);
    }

    public static Date operationYear(Date date, int num) {
        return operationDate(date, Calendar.YEAR, num);
    }

    public static Date operationMoth(int num) {
        return operationDate(new Date(), Calendar.MONTH, num);
    }

    public static Date operationMoth(Date date, int num) {
        return operationDate(date, Calendar.MONTH, num);
    }

    public static Date operationDay(int num) {
        return operationDate(new Date(), Calendar.DATE, num);
    }

    public static Date operationDay(Date date, int num) {
        return operationDate(date, Calendar.DATE, num);
    }

    public static Date operationHour(int num) {
        return operationDate(new Date(), Calendar.HOUR, num);
    }

    public static Date operationHour(Date date, int num) {
        return operationDate(date, Calendar.HOUR, num);
    }

    public static Date operationMinute(int num) {
        return operationDate(new Date(), Calendar.MINUTE, num);
    }

    public static Date operationMinute(Date date, int num) {
        return operationDate(date, Calendar.MINUTE, num);
    }

    public static Date operationSecond(int num) {
        return operationDate(new Date(), Calendar.SECOND, num);
    }

    public static Date operationSecond(Date date, int num) {
        return operationDate(date, Calendar.SECOND, num);
    }

    public static Date operationMillisecond(int num) {
        return operationDate(new Date(), Calendar.MILLISECOND, num);
    }

    public static Date operationMillisecond(Date date, int num) {
        return operationDate(date, Calendar.MILLISECOND, num);
    }

    public static Date operationDate(int field, int num) {
        GregorianCalendar gc = new GregorianCalendar();
        gc.setTime(new Date());
        gc.add(field, num);
        return gc.getTime();
    }

    public static Date operationDate(Date date, int field, int num) {
        GregorianCalendar gc = new GregorianCalendar();
        gc.setTime(date);
        gc.add(field, num);
        return gc.getTime();
    }

    public static void main(String[] args) {

        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date endDate = sdf.parse("2024-12-08");
            System.out.println(isMonday(endDate));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 两天之间的天数
     *
     * @param date1
     * @param date2
     * @return
     */
    public static int getDateBetween(Date date1, Date date2) {
        Long date1Long = date1.getTime();
        Long date2Long = date2.getTime();
        Long betweenMilli = date2Long - date1Long;
        Long day = betweenMilli / (3600 * 1000 * 24);
        return Integer.valueOf(day + "");
    }

    public static Date getPureDate(Date date) throws Exception {

        SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);

        String str = sdf.format(date);

        return sdf.parse(str);
    }

    public static Date getMonthStart(Date date) {
        if (date == null) {
            date = new Date();
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DATE, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    public static Date getMonthEnd(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(DateUtil.getMonthStart(date));
        calendar.add(Calendar.MONTH, 1);
        return calendar.getTime();
    }

    public static Date addDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, 1);
        return calendar.getTime();
    }

    public static Date addDate(Date date, Integer interval) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, interval);
        return calendar.getTime();
    }

    public static Date addHour(Date date, Integer interval) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.HOUR, interval);
        return calendar.getTime();
    }

    public static int getHour(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.HOUR_OF_DAY);
    }

    public static Date getThisWeekMonday(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        // 设置星期的第一天为周一
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        // 调整到本周的周一
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        // 设置为 00:00:00
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    public static Date addSecond(Date date, int seconds) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.SECOND, seconds);
        return calendar.getTime();
    }

    // 判断是否是“周一凌晨 0点到1点前”的时间
    public static boolean isEarlyMonday(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);

        int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); // 周日=1，周一=2...
        int hour = cal.get(Calendar.HOUR_OF_DAY);       // 0-23
        int minute = cal.get(Calendar.MINUTE);          // 0-59

        // 周一凌晨 0:00 ~ 0:59
        return (dayOfWeek == Calendar.MONDAY) && (hour == 0);
    }

    /**
     * 时区转化
     *
     * @param timeZone   时区 比如GMT+8
     * @param createTime 时间戳
     * @return
     */
    public static String convertDateBetweenTimeZone(String timeZone, Long createTime) {
        return convertDateBetweenTimeZone(timeZone, new Date(createTime));
    }

    /**
     * 时区转化
     *
     * @param timeZone 时区 比如GMT+8
     * @param date     时间
     * @return
     */
    public static String convertDateBetweenTimeZone(String timeZone, Date date) {

        return convertDateBetweenTimeZone(timeZone, date, TIME_FORMAT);
    }

    public static String convertDateBetweenTimeZone(String timeZone, Date date, String format) {
        DateFormat dateFormat = new SimpleDateFormat("Z");
        String localTimeZone = dateFormat.format(new Date());
        TimeZone srcTimeZone = TimeZone.getTimeZone("GMT" + localTimeZone);
        TimeZone destTimeZone = TimeZone.getTimeZone(timeZone);
        String destDateTime = dateTransformBetweenTimeZone(date, format, srcTimeZone, destTimeZone);
        return destDateTime;
    }

    public static long getTimestampByZero() {
        return getTimestampByZero(new Date());
    }

    public static long getTimestampByZero(Date date) {
        DateFormat dateFormat = new SimpleDateFormat("Z");
        String localTimeZone = dateFormat.format(new Date());
        TimeZone srcTimeZone = TimeZone.getTimeZone("GMT" + localTimeZone);
        TimeZone destTimeZone = TimeZone.getTimeZone("GMT +0");
        Long targetTime = date.getTime() - srcTimeZone.getRawOffset() + destTimeZone.getRawOffset();
        return targetTime;
    }

    public static long getTimestampByChina() {

        return getTimestampByLocale(Locale.CHINA);
    }

    public static long getTimestampByLocale(Locale aLocale) {
        Calendar cal = Calendar.getInstance(aLocale);
        return DateUtil.getTimestamp(cal.getTime());
    }

    public static long getTimestampByTimeZone(TimeZone zone) {
        Calendar cal = Calendar.getInstance(zone);
        return DateUtil.getTimestamp(cal.getTime());
    }

    /**
     * @param sourceDate     转化时区时间
     * @param format         转化后格式
     * @param sourceTimeZone
     * @param targetTimeZone
     * @return
     */
    public static String dateTransformBetweenTimeZone(Date sourceDate, String format,
                                                      TimeZone sourceTimeZone, TimeZone targetTimeZone) {
        //计算出对应时区的时间
        Long targetTime = sourceDate.getTime() - sourceTimeZone.getRawOffset() + targetTimeZone.getRawOffset();
        //时间格式转化
        return format(format, new Date(targetTime));
    }

    /**
     * 获取时间戳
     *
     * @return
     */
    public static String getTimestamp() {
        return String.valueOf(System.currentTimeMillis() / 1000);
    }

    public static long getTimestamp(Date sourceDate) {
        if (sourceDate == null) {
            return 0;
        }
        return sourceDate.getTime();
    }

    public static long getTimestamp(String orient) {

        return getTimestamp(parseTime(orient));
    }

    public static List<String> shardingDate(Date startDate, Date endDate) throws Exception {

        if (startDate == null) {
            throw new Exception("Start date can not by empty");
        }
        if (endDate == null) {
            throw new Exception("End date can not by empty");
        }
        if (endDate.getTime() < startDate.getTime()) {
            throw new Exception("End date must greater than start date");
        }

        List<String> shardings = Lists.newArrayList();
        Calendar sc = Calendar.getInstance();
        sc.setTime(startDate);
        Calendar ec = Calendar.getInstance();
        ec.setTime(endDate);
//        if (ec.get(Calendar.DATE) == 1) {
//            ec.set(Calendar.DATE, -1);
//        }

        if (ec.get(Calendar.DAY_OF_MONTH) == 1) {
            ec.add(Calendar.DAY_OF_MONTH, -1);
        }

        int sYear = sc.get(Calendar.YEAR);
        int eYear = ec.get(Calendar.YEAR);
        int sMonth = sc.get(Calendar.MONTH) + 1;
        int eMonth = ec.get(Calendar.MONTH) + 1;

        for (int y = sYear; y <= eYear; y++) {
            for (int m = (y == sYear ? sMonth : 1); (y != eYear && m <= 12) || (y == eYear && m <= eMonth); m++) {
                shardings.add(yearAndMonthToString(y, m));
            }
        }

        Collections.reverse(shardings);
        return shardings.stream().distinct().collect(Collectors.toList());
    }

    private static String yearAndMonthToString(int year, int month) throws Exception {
        return String.format("%d%s", year, month < 10 ? String.format("0%d", month) : String.valueOf(month));
    }

    public static DateIntervalEntity generateYesterdayInterval(Date date) throws Exception {
        DateIntervalEntity entity = new DateIntervalEntity();
        Date pureDate = DateUtil.getPureDate(date);
        entity.setEndDate(pureDate);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(pureDate);
        calendar.add(Calendar.DATE, -1);
        entity.setStartDate(calendar.getTime());
        return entity;
    }

    public static boolean isMonday(Date date) throws Exception {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int dow = calendar.get(Calendar.DAY_OF_WEEK);
        return dow == 2;
    }

    public static boolean isMonthStart(Date date) throws Exception {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int dow = calendar.get(Calendar.DAY_OF_MONTH);
        return dow == 1;
    }

    public static Integer getDayOfWeek(Date date) throws Exception {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.DAY_OF_WEEK);
    }

    public static Date addMonth(Date date, Integer interval) throws Exception {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, interval);
        return calendar.getTime();
    }


    public static Integer monthBetween(Date startDate, Date endDate) throws Exception {
        Calendar startCalendar = Calendar.getInstance();
        startCalendar.setTime(DateUtil.getPureDate(startDate));
        Calendar endCalendar = Calendar.getInstance();
        endCalendar.setTime(DateUtil.getPureDate(endDate));

        int yearBetween = endCalendar.get(Calendar.YEAR) - startCalendar.get(Calendar.YEAR);
        return (endCalendar.get(Calendar.MONTH) + 12 * yearBetween) - startCalendar.get(Calendar.MONTH);
    }

    public static Integer getMonth(Date date) throws Exception {
        // 获取Calendar实例
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        // 获取月份，注意月份是从0开始的，即0代表1月，11代表12月
        int month = calendar.get(Calendar.MONTH);
        // 如果需要从1开始计数，可以加1
        int monthPlusOne = month + 1;

        return monthPlusOne;
    }

    /**
     * 毫秒时间戳转换
     *
     * @author gao
     * @date 2025/8/15 14:11
     */
    public static String formatTimestamp(Long timestamp) {
        if (timestamp == null) {
            return null;
        }

        // 创建 DateTimeFormatter
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // 转换时间戳为 LocalDateTime
        LocalDateTime dateTime = LocalDateTime.ofInstant(
                java.time.Instant.ofEpochMilli(timestamp),
                ZoneId.systemDefault()
        );

        // 格式化输出
        return dateTime.format(formatter);
    }

    public static String formatToYm(Date date) {
        return format("yyyyMM", date);
    }

}