package org.jeecg.modules.adweb.common.util;

import com.xkcoding.http.util.StringUtil;

import lombok.extern.slf4j.Slf4j;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;

/**
 * AdWeb时间工具类
 *
 * <p>其它场景，参考 {@link org.jeecg.common.util.DateUtils}
 *
 * @author wfansh
 */
@Slf4j
public class DateUtil {

    /** 时间格式(yyyy-MM-dd) */
    public static final String DATE_PATTERN = "yyyy-MM-dd";

    /** 时间格式(yyyy-MM-dd HH:mm:ss) */
    public static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

    /** 带时区的时间格式(yyyy-MM-dd HH:mm:ss +00:00) */
    public static final String ZONED_DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss X";

    public static final String SUBJECT_DATE = "yyyy/MM/dd";

    public static final ZoneId DEFAULT_ZONE_ID = ZoneId.of("Asia/Shanghai");

    /** yyyy-MM-dd HH:mm:ss. */
    public static final String DATE_FORMAT_FIVE = "yyyy-MM-dd HH:mm:ss";

    /** yyyyMMdd. */
    public static final String DATE_FORMAT_THREE = "yyyyMMdd";

    /** yyyyMMddHHmm */
    public static final String DATE_FORMAT = "yyyyMMddHHmmss";

    public static Date plusDays(Date date, int daysToAdd) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        calendar.add(Calendar.DAY_OF_MONTH, daysToAdd);
        return calendar.getTime();
    }

    /**
     * 特殊时间数据处理
     *
     * @param dateType 时间
     */
    public static Map<String, Date> dealDateType(String dateType) {
        Date now = new Date();
        Date start = null;
        Date end = null;
        if ("yesterday".equals(dateType)) {
            start = getTodayZeroTime(DateUtil.addDays(now, -1));
            end = getTodayZeroTime(now);
        }
        if ("today".equals(dateType)) {
            start = getTodayZeroTime(now);
            end = getTmrZeroTime(now);
        }
        if ("sevenDay".equals(dateType)) {
            end = getTmrZeroTime(now);
            start = addDays(end, -7);
        }
        if ("thirtyDay".equals(dateType)) {
            end = getTmrZeroTime(now);
            start = addDays(end, -30);
        }
        Map<String, Date> map = new HashMap<>();
        map.put("start", start);
        map.put("end", end);
        return map;
    }

    /**
     * 获取当日零点
     *
     * @param date
     * @return
     */
    public static Date getTodayZeroTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        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();
    }

    /**
     * 获取明日零点
     *
     * @param date
     * @return
     */
    public static Date getTmrZeroTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        return calendar.getTime();
    }

    /**
     * 在当前日期上追加N天
     *
     * @param date 当前日期
     * @param num 添加天数
     * @return 日期字符串形式
     */
    public static Date addDays(Date date, int num) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.DAY_OF_MONTH, num);
        return c.getTime();
    }

    /**
     * 按指定格式转化字符串为Date
     *
     * @param strDate String
     * @param strFormat String
     * @return FormatDate
     * @throws ParseException ParseException
     */
    public static Date getFormatDate(String strDate, String strFormat) throws ParseException {
        if (StringUtil.isEmpty(strDate) || StringUtil.isEmpty(strFormat)) {
            return null;
        }

        SimpleDateFormat df = new SimpleDateFormat(strFormat);
        df.setLenient(false);
        return df.parse(strDate);
    }

    /**
     * 按指定格式转化Date为字符串
     *
     * @param date Date
     * @param toFormat String
     * @return FormatDate String
     */
    public static String dateToString(Date date, String toFormat) {

        if (date == null) {
            return "";
        }

        SimpleDateFormat df = new SimpleDateFormat(toFormat);
        df.setLenient(false);
        return df.format(date);
    }

    /**
     * 转换为指定格式Date
     *
     * @param date String
     * @param strFormat String
     * @return FormatDate
     * @throws ParseException ParseException
     */
    public static Date formatDate(Date date, String strFormat) {
        if (date == null) {
            return null;
        }
        Date reDate = null;
        try {
            reDate = getFormatDate(dateToString(date, strFormat), strFormat);
        } catch (ParseException e) {
            date = null;
        }
        return reDate;
    }

    /**
     * 计算两个Date的日期差
     *
     * @param start
     * @param end
     * @return
     */
    public static int diffDays(Date start, Date end) {
        return (int)
                ChronoUnit.DAYS.between(
                        LocalDate.ofInstant(end.toInstant(), DEFAULT_ZONE_ID),
                        LocalDate.ofInstant(start.toInstant(), DEFAULT_ZONE_ID));
    }

    /**
     * 根据指定格式，将Date转化为为字符串
     *
     * @param date
     * @param format
     * @return
     */
    public static String formatDateStr(Date date, String format) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(format);
        dateFormat.setLenient(false);
        return dateFormat.format(date);
    }

    /**
     * 根据指定格式，将字符串解析为Date
     *
     * @param dateStr
     * @param format
     * @return
     * @throws ParseException
     */
    public static Date parseDate(String dateStr, String format) {
        try {
            SimpleDateFormat dateFormat = new SimpleDateFormat(format);
            dateFormat.setLenient(false);
            return dateFormat.parse(dateStr);
        } catch (ParseException e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }
}
