package cn.chnmuseum.party.common.util;

import jdk.nashorn.internal.parser.DateParser;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class TimeUtils {

    // 格式:年-月-日 小时:分钟:秒
    public static final String FORMAT_ONE = "yyyy-MM-dd HH:mm:ss";

    public static final String FORMAT_T = "yyyy-MM-ddTHH:mm:ss";

    // 格式:年-月-日 小时:分钟
    public static final String FORMAT_TWO = "yyyy-MM-dd HH:mm";

    // 格式:年-月-日
    public static final String LONG_DATE_FORMAT = "yyyy-MM-dd";

    // 格式:月-日
    public static final String SHORT_DATE_FORMAT = "MM-dd";

    // 格式:小时:分钟:秒
    public static final String LONG_TIME_FORMAT = "HH:mm:ss";

    // 格式:年-月
    public static final String MONTG_DATE_FORMAT = "yyyy-MM";

    // 格式:年-月
    public static final String Chinese_DATE_FORMAT = "yyyy年MM月dd日 HH:mm";

    private static final ConcurrentMap<String, DateTimeFormatter> FORMATTER_CACHE = new ConcurrentHashMap<>();

    private static final int PATTERN_CACHE_SIZE = 500;

    public static LocalDate getCurrentDate = LocalDate.now();
    public static LocalTime getCurrentTime = LocalTime.now().withNano(0);

    /**
     * Date转换为long
     *
     * @param date date
     * @return
     */
    public static long parseDate(Date date) {
        return date.getTime() / 1000L;
    }

    /**
     * Date转换为格式化时间
     *
     * @param date    date
     * @param pattern 格式
     * @return
     */
    public static String format(Date date, String pattern) {
        return format(LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()), pattern);
    }

    /**
     * localDateTime转换为格式化时间
     *
     * @param localDateTime localDateTime
     * @param pattern       格式
     * @return
     */
    public static String format(LocalDateTime localDateTime, String pattern) {
        DateTimeFormatter formatter = createCacheFormatter(pattern);
        return localDateTime.format(formatter);
    }

    /**
     * 格式化字符串转为Date
     *
     * @param time    格式化时间
     * @param pattern 格式
     * @return
     */
    public static Date parseDate(String time, String pattern) {
        return Date.from(parseLocalDateTime(time, pattern).atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 格式化字符串转为LocalDateTime
     *
     * @param time    格式化时间
     * @param pattern 格式
     * @return
     */
    public static LocalDateTime parseLocalDateTime(String time, String pattern) {
        DateTimeFormatter formatter = createCacheFormatter(pattern);
        return LocalDateTime.parse(time, formatter);
    }

    /**
     * 将某时间字符串转为自定义时间格式的LocalDateTime
     *
     * @param time
     * @param format
     * @return
     */
    public static LocalDateTime parseStringToDateTime(String time, String format) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern(format);
        return LocalDateTime.parse(time, df);
    }

    /**
     * java.util.Date --> java.time.LocalDateTime
     */
    public static LocalDateTime UDateToLocalDateTime(Date date) {
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        return LocalDateTime.ofInstant(instant, zone);
    }

    /**
     * 将LocalDateTime转为自定义的时间格式的字符串
     *
     * @param localDateTime
     * @param format
     * @return
     */
    public static String getDateTimeAsString(LocalDateTime localDateTime, String format) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
        return localDateTime.format(formatter);
    }

    /**
     * 将long类型的timestamp转为LocalDateTime
     *
     * @param timestamp
     * @return
     */
    public static LocalDateTime getDateTimeOfTimestamp(long timestamp) {
        Instant instant = Instant.ofEpochMilli(timestamp);
        ZoneId zone = ZoneId.systemDefault();
        return LocalDateTime.ofInstant(instant, zone);
    }

    /**
     * 将LocalDateTime转为long类型的timestamp
     *
     * @param localDateTime
     * @return
     */
    public static long getTimestampOfDateTime(LocalDateTime localDateTime) {
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDateTime.atZone(zone).toInstant();
        return instant.toEpochMilli();
    }

    public static long getTimestampOfDateTime8(LocalDateTime localDateTime) {
        ZoneId zone = ZoneId.of("Asia/Shanghai");
        Instant instant = localDateTime.atZone(zone).toInstant();
        return instant.toEpochMilli();
    }

    /**
     * 在缓存中创建DateTimeFormatter
     *
     * @param pattern 格式
     * @return
     */
    private static DateTimeFormatter createCacheFormatter(String pattern) {
        if (pattern == null || pattern.length() == 0) {
            throw new IllegalArgumentException("Invalid pattern specification");
        }
        DateTimeFormatter formatter = FORMATTER_CACHE.get(pattern);
        if (formatter == null) {
            if (FORMATTER_CACHE.size() < PATTERN_CACHE_SIZE) {
                formatter = DateTimeFormatter.ofPattern(pattern);
                DateTimeFormatter oldFormatter = FORMATTER_CACHE.putIfAbsent(pattern, formatter);
                if (oldFormatter != null) {
                    formatter = oldFormatter;
                }
            }
        }

        return formatter;
    }

    /**
     * 解析时间字符串
     *
     * @param dateString ECMA 5.1 DateString
     */
    public static LocalDateTime parseUTCDateTime(String dateString) {
        DateParser dateParser = new DateParser(dateString);
        if (dateParser.parse()) {
            Integer[] dateFields = dateParser.getDateFields();
            LocalDateTime localDateTime = LocalDateTime.of(dateFields[0], dateFields[1] + 1, dateFields[2], dateFields[3], dateFields[4], dateFields[5], dateFields[6]);
            if (dateFields[7] != null) {
                return localDateTime.minusMinutes(dateFields[7]);
            }
            return localDateTime;
        }
        throw new DateTimeParseException("解析时间出现错误:" + dateString, dateString, 0);
    }

    public static ZonedDateTime parseZonedDateTime(String dateString) {
        DateParser dateParser = new DateParser(dateString);
        if (dateParser.parse()) {
            Integer[] dateFields = dateParser.getDateFields();
            if (dateFields[7] != null) {
                return ZonedDateTime.of(dateFields[0], dateFields[1] + 1, dateFields[2], dateFields[3], dateFields[4], dateFields[5], dateFields[6], ZoneId.ofOffset("", ZoneOffset.ofHoursMinutes(dateFields[7] / 60, dateFields[7] % 60)));
            }
            return ZonedDateTime.of(dateFields[0], dateFields[1] + 1, dateFields[2], dateFields[3], dateFields[4], dateFields[5], dateFields[6], ZoneId.systemDefault());
        }
        throw new DateTimeParseException("解析时间出现错误:" + dateString, dateString, 0);
    }

    /**
     * Date转换为LocalDateTime
     *
     * @param date
     */
    public static LocalDateTime date2LocalDateTime(Date date) {
        Instant instant = date.toInstant();//An instantaneous point on the time-line.(时间线上的一个瞬时点。)
        ZoneId zoneId = ZoneId.systemDefault();//A time-zone ID, such as {@code Europe/Paris}.(时区)
        return instant.atZone(zoneId).toLocalDateTime();
    }

    /**
     * LocalDateTime转换为Date
     *
     * @param localDateTime
     */
    public static Date localDateTime2Date(LocalDateTime localDateTime) {
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = localDateTime.atZone(zoneId);//Combines this date-time with a time-zone to create a  ZonedDateTime.
        return Date.from(zdt.toInstant());
    }

    /**
     * 取本月第一天
     */
    public static LocalDate firstDayOfThisMonth() {
        LocalDate today = LocalDate.now();
        return today.with(TemporalAdjusters.firstDayOfMonth());
    }

    /**
     * 取本月第N天
     */
    public static LocalDate dayOfThisMonth(int n) {
        LocalDate today = LocalDate.now();
        return today.withDayOfMonth(n);
    }

    /**
     * 取本月最后一天
     */
    public static LocalDate lastDayOfThisMonth() {
        LocalDate today = LocalDate.now();
        return today.with(TemporalAdjusters.lastDayOfMonth());
    }

    /**
     * 取本月第一天的开始时间
     */
    public static LocalDateTime startOfThisMonth() {
        return LocalDateTime.of(firstDayOfThisMonth(), LocalTime.MIN);
    }

    /**
     * 取本月最后一天的结束时间
     */
    public static LocalDateTime endOfThisMonth() {
        return LocalDateTime.of(lastDayOfThisMonth(), LocalTime.MAX);
    }

    /**
     * 取N天后
     */
    public static LocalDateTime plusDays(int days) {
        LocalDateTime now = LocalDateTime.now();
        return now.plusDays(days);
    }

    /**
     * 取N小时后
     */
    public static LocalDateTime plusHours(int hours) {
        LocalDateTime now = LocalDateTime.now();
        return now.plusHours(hours);
    }

    /**
     * 取N小时后
     */
    public static long plusHours(long timestamp, int hours) {
        return timestamp + hours * 60 * 60;
    }

}