package com.usoftchina.dingtalk.sdk.util;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.TemporalField;
import java.time.temporal.WeekFields;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;

/**
 * @author yingp
 * @date 2019/9/11
 */
public class DateUtils {

    private final static Map<String, DateFormat> formats = new ConcurrentHashMap<>();
    private final static Pattern P_YMD = Pattern.compile("\\d{4}-\\d{2}-\\d{2}");
    private final static Pattern P_YMD_HMS = Pattern.compile("\\d{4}-\\d{2}-\\d{2}\\s\\d{2}:\\d{2}:\\d{2}");
    private final static Pattern P_YMD_HMS_TZ = Pattern.compile("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z");

    private static DateFormat getFormat(String pattern, TimeZone timeZone) {
        DateFormat format = formats.get(pattern + "_" + timeZone.getID());
        if (null == format) {
            format = new SimpleDateFormat(pattern);
            format.setTimeZone(timeZone);
            formats.put(pattern + "_" + timeZone.getID(), format);
        }
        return format;
    }

    public static String format(Date date, String pattern) {
        return getFormat(pattern, TimeZone.getDefault()).format(date);
    }

    public static String format(Date date) {
        return format(date, "yyyy-MM-dd");
    }

    public static String format(long time) {
        return format(new Date(time));
    }

    public static String formatDateTime(Date date) {
        return format(date, "yyyy-MM-dd HH:mm:ss");
    }

    public static String formatDateTime(long time) {
        return formatDateTime(new Date(time));
    }

    public static Date parse(String date) {
        try {
            if (P_YMD.matcher(date).matches()) {
                return getFormat("yyyy-MM-dd", TimeZone.getDefault()).parse(date);
            } else if (P_YMD_HMS.matcher(date).matches()) {
                return getFormat("yyyy-MM-dd HH:mm:ss", TimeZone.getDefault()).parse(date);
            } else if (P_YMD_HMS_TZ.matcher(date).matches()) {
                return getFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", TimeZone.getTimeZone("UTC")).parse(date);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 今天日期开始（00:00:00）
     *
     * @return
     */
    public static Date nowDateStart() {
        return Date.from(LocalDate.now().atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 今天日期截止（23:59:59）
     *
     * @return
     */
    public static Date nowDateEnd() {
        return Date.from(LocalDateTime.of(LocalDate.now(), LocalTime.MAX)
                .atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 今天（含时间）
     *
     * @return
     */
    public static Date nowDateTime() {
        return new Date();
    }

    /**
     * 日期起始（00:00:00）
     *
     * @return
     */
    public static Date startOfDate(Date date) {
        return Date.from(date.toInstant().atZone(ZoneId.systemDefault())
                .toLocalDate().atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 日期截止（23:59:59）
     *
     * @return
     */
    public static Date endOfDate(Date date) {
        return Date.from(
                LocalDateTime.of(date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), LocalTime.MAX)
                        .atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 周一
     *
     * @return
     */
    public static Date nowWeekStart() {
        LocalDate now = LocalDate.now();
        TemporalField fieldISO = WeekFields.of(Locale.FRANCE).dayOfWeek();
        return Date.from(now.with(fieldISO, 1).atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 周天
     *
     * @return
     */
    public static Date nowWeekEnd() {
        LocalDate now = LocalDate.now();
        TemporalField fieldISO = WeekFields.of(Locale.FRANCE).dayOfWeek();
        return Date.from(
                LocalDateTime.of(now.with(fieldISO, 7), LocalTime.MAX)
                        .atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 月初
     *
     * @return
     */
    public static Date nowMonthStart() {
        LocalDate date = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());
        return Date.from(date.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 月末
     *
     * @return
     */
    public static Date nowMonthEnd() {
        LocalDate date = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());
        return Date.from(LocalDateTime.of(date, LocalTime.MAX).atZone(ZoneId.systemDefault()).toInstant());
    }
}
