package com.zzwtec.third.utils;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;

import static java.util.Calendar.*;

/**
 * create by Jomchen on 2018/11/29
 */
public class TimeUtil {
    public static final long defaultYearMonthDay = 10000101; // 1000年01月01日

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

    // yyyyMMddHHmmss
    public static final String NOW_TIME_2 = "yyyyMMddHHmmss";
    // yyyyMMddHHmmss
    public static final String NOW_TIME_3 = "yyyyMMddHHmm";
    // yyyyMMdd
    public static final String THIS_DAY_TIME = "yyyyMMdd";
    // yyyyMM
    public static final String THIS_MONTH_TIME = "yyyyMM";
    // yyyy
    public static final String THIS_YEAR_TIME = "yyyy";

    // M月d日 HH:mm:ss
    public static final String WX_NOW_TIME = "M月d日 HH:mm:ss";

    public static final String HHMMSS = "HH:mm:ss";

    private static final long A_DAY_IN_MILLIS = 1000 * 60 * 60 * 24;

    private static final Logger logger = LoggerFactory.getLogger(TimeUtil.class);
    public final static String dateFormat1 = "yyyyMMdd";
    public final static String dateFormat2 = "yyyy-MM-dd";
    public final static String dateFormat3 = "yyyy/MM/dd";
    private static SimpleDateFormat sdf1 = new SimpleDateFormat(dateFormat1);
    private static SimpleDateFormat sdf2 = new SimpleDateFormat(dateFormat2);
    private static SimpleDateFormat sdf3 = new SimpleDateFormat(dateFormat3);
    private static SimpleDateFormat sdf4 = new SimpleDateFormat(NOW_TIME_1);
    private static SimpleDateFormat sdf5 = new SimpleDateFormat();

    public static Calendar getCalendar(long millis) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date(millis));
        return calendar;
    }



    public static Date parse(String format, String date) {
        try {
            return new SimpleDateFormat(format).parse(date);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    public static String format(String format, Date date) {
        return new SimpleDateFormat(format).format(date);
    }

    /**
     * 获取当前时间 格式为 yyyy-MM-dd HH:mm:ss
     * @return
     */
    public static String getCurrentTime() {
        return format(NOW_TIME_1, new Date());
    }

    /**
     * 获取当前时间
     * @return 返回当前时间格式为yyyyMMddHHmmss的long型，如20151231235900
     */
    public static long getNowTime() {
        return Long.parseLong(format(NOW_TIME_2, new Date()));
    }
    /**
     * 获取当前时间
     * @return 返回当前时间格式为yyyyMMddHHmmss的long型，如201512312359
     */
    public static long getNowMinTime() {
        return Long.parseLong(format(NOW_TIME_3, new Date()));
    }
    /**
     * 获取几个月前时间
     * @param mouth 几个月前 主要是负数 如一个月前 则为-1
     * @return 返回当前时间格式为yyyyMMddHHmmss的long型，如20151231235900
     */
    public static long getSomeMonthsAgoTime(int mouth) {
        Date dNow = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(dNow);
        calendar.add(Calendar.MONTH, mouth);
        return Long.parseLong(format(NOW_TIME_2, calendar.getTime()));
    }

    /**
     * 获取当月时间
     * @return 返回当前时间格式为yyyyMMddHHmmss的long型，如当天是2017年6月13日11点55分10秒，返回20170600000000
     */
    public static long getThisMonthsTime() {
        long thisMonthsTime = Long.parseLong(format(THIS_MONTH_TIME, new Date()));
        thisMonthsTime *= 100000000l;
        return thisMonthsTime;
    }

    /**
     * 获取今年开始时间 如果现在是 2018-09-06 19:21:03，那么结果是20180101000000
     * @return
     */
    public static long getThisYearStartTime(){
        long thisYearTime = Long.parseLong(format(THIS_YEAR_TIME, new Date()));
        thisYearTime = thisYearTime * 10000000000l + 101000000l;
        return thisYearTime;

    }

    /**
     * 将时间格式为yyyyMMddHHmmss的long型转为 LocalDateTime，如20151231235923
     * @param time
     * @return
     */
    public static LocalDateTime long2LocalDateTime(long time){
        int year = (int)(time / 10000000000l) ;
        int month = (int)((time - year * 10000000000l) / 100000000l) ;
        int dayOfMonth = (int)((time - year * 10000000000l - month * 100000000l) / 1000000l) ;
        int hour = (int)((time - year * 10000000000l - month * 100000000l - dayOfMonth * 1000000l) / 10000l) ;
        int minute = (int)((time - year * 10000000000l - month * 100000000l - dayOfMonth * 1000000l - hour * 10000l) / 100l) ;
        int second = (int)(time - year * 10000000000l - month * 100000000l - dayOfMonth * 1000000l - hour * 10000l - minute * 100l) ;
        return LocalDateTime.of(year, month, dayOfMonth, hour, minute, second);
    }

    /**
     * 从时间格式为yyyyMMddHHmmss的long型中获取小时，如20151231235923返回23
     * @param time
     * @return
     */
    public static int getHourFromTime(long time){
        int year = (int)(time / 10000000000l) ;
        int month = (int)((time - year * 10000000000l) / 100000000l) ;
        int dayOfMonth = (int)((time - year * 10000000000l - month * 100000000l) / 1000000l) ;
        return (int)((time - year * 10000000000l - month * 100000000l - dayOfMonth * 1000000l) / 10000l) ;
    }

    /**
     * 获取今年开始时间 如果现在是 2018-09-06 19:21:03，那么结果是20180906000000
     * @return
     */
    public static long getThisDayStartTime(){
        long thisDayTime = Long.parseLong(format(THIS_DAY_TIME, new Date()));
        thisDayTime = thisDayTime * 1000000l;
        return thisDayTime;

    }
    /**
     * 获取指定时间开始时间 如果是 2018-09-06 19:21:03，那么结果是20180906000000
     * @return
     */
    public static long getDayStartTime(long time){
        long thisDayTime = time / 1000000l;
        thisDayTime = thisDayTime * 1000000l;
        return thisDayTime;

    }

    /**
     * 获取当前时间
     * @return 返回当前时间格式为M月d日 HH:mm:ss，如5月11日 18:00:00
     */
    public static String getWxNowTime() {
        return format(WX_NOW_TIME, new Date());
    }

    /**
     * 获取将yyyyMMddHHmmss的long型转为M月d日 HH:mm:ss，如5月11日 18:00:00
     */
    public static String getWxTime(long time) {
        String timeStr = timeLong2Str(time);
        timeStr = timeStr.substring(5).replace("-", "月").replace(" ", "日 ");
        if (timeStr.startsWith("0")) {
            timeStr = timeStr.substring(1);
        }
        timeStr = timeStr.replace("月0", "月");
        return timeStr;
    }

    /**
     * 时间转换 将long转为字符串 即将 "20151231235900" 转为 "2015-12-31 23:59:00"
     * @param time
     * @return
     */
    public static String timeLong2Str(long time) {
        if(StringUtil.notEmpty(time)){
            String result = "";
            StringBuffer datestr=new StringBuffer(String.valueOf(time));
            if(datestr.length() == 14){
                result=datestr.insert(4, "-").insert(7, "-").insert(10, " ").insert(13, ":").insert(16, ":").toString();
            }else if(datestr.length() == 8) {
                result=datestr.insert(4, "-").insert(7, "-").toString();
            }
            return result;
        }else {
            return String.valueOf(time);
        }

    }

    /**
     * 时间转换 将long转为字符串 即将 "20151231235900" 转为 "20151231"
     * @param time
     * @return
     */
    public static String timeLong2yyyyMMddStr(long time) {
        return String.valueOf(time / 1000000);
    }

    public static boolean isValidDate(String str) {
        if (StringUtils.isEmpty(str)){
            return false;
        }
        boolean convertSuccess = true;
        try {
            synchronized (sdf4){
                // 设置lenient为false.
                // 否则SimpleDateFormat会比较宽松地验证日期，比如2007/02/29会被接受，并转换成2007/03/01
                sdf4.setLenient(false);
                sdf4.parse(str);
            }
        } catch (ParseException e) {
            // e.printStackTrace();
            // 如果throw java.text.ParseException或者NullPointerException，就说明格式不对
            convertSuccess = false;
        }
        return convertSuccess;
    }

    public static boolean isValidDate(String str,String pattern) {
        if (StringUtils.isEmpty(str) || StringUtils.isEmpty(pattern)){
            return false;
        }
        boolean convertSuccess = true;
        try {
            synchronized (sdf5){
                // 设置lenient为false.
                // 否则SimpleDateFormat会比较宽松地验证日期，比如2007/02/29会被接受，并转换成2007/03/01
                sdf5.applyPattern(pattern);
                sdf5.setLenient(false);
                sdf5.parse(str);
            }
        } catch (ParseException e) {
            // e.printStackTrace();
            // 如果throw java.text.ParseException或者NullPointerException，就说明格式不对
            convertSuccess = false;
        }
        return convertSuccess;
    }

    /**
     * 时间转换 将字符串转为long 即将 "2015-12-31 23:59:00" 转为 "20151231235900"
     * @return
     */
    public static long timeStr2Long(String timeStr) {
        if (timeStr == null || timeStr.length() == 0) {
            return 0;
        }
        timeStr = timeStr.replaceAll("-", "").replaceAll(":", "").replaceAll(" ", "");
        long time = Long.parseLong(timeStr);
        return time;
    }

    /**
     * 时间转换 根据不同样式的字符串转为long，即将 "2015-12-31 23:59:00" 转为 "20151231235900"
     * 且对字符串要求较为严格，类似于 2015-13-01这类的无法转换会返回0
     *
     * @param timeStr 时间字符串
     * @param pattern 时间模板
     * @return 时间戳数字
     * @author wxy
     */
    public static long timeStr2Long(String timeStr, String pattern) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
        simpleDateFormat.setLenient(false);
        try {
            Date parse = simpleDateFormat.parse(timeStr);
            String format = format(NOW_TIME_2, parse);
            return Long.parseLong(format);
        } catch (ParseException e) {
            return 0;
        }
    }

    /**
     * 检测时间是否符合要求
     * @param time 时间格式是yyyy-MM-dd HH:mm:ss
     * @return
     */
    public static boolean checkTimeStr(String time) {
        return CharUtil.characterDetection(time, CharUtil.TIME_LSDF_MATCH);
    }

    /**
     * 检测时间是否符合要求
     * @param time 时间格式是yyyyMMddHHmmss
     * @return
     */
    public static boolean checkTimeData(String time) {
        return CharUtil.characterDetection(time, CharUtil.TIME_NOWTIMEDF_MATCH);
    }

    /**
     * 判断当前时间是否在一个时间范围内
     * @param startTime
     * @param endTime
     * @return
     */
    public static boolean isInTimeScope(String startTime, String endTime) {
        return isInTimeScope(System.currentTimeMillis(), startTime, endTime);
    }

    /**
     * 判断一个时间是否处于一个时间范围内
     * @param aTime
     * @param startTime
     * @param endTime
     * @return
     */
    public static boolean isInTimeScope(String aTime, String startTime, String endTime) {
        return isInTimeScope(parse(NOW_TIME_1, aTime).getTime(), startTime, endTime);
    }

    /**
     * 判断一个时间是否处于一个时间范围内
     * 如果不能解析起始或结束时间，则返回false
     * 如果起始和结束时间一样，则返回false
     * @param aTime
     * @param startTime
     * @param endTime
     * @return
     */
    public static boolean isInTimeScope(long aTime, String startTime, String endTime) {
        // 设置给定的时间
        Calendar aCalendar = getCalendar(aTime);
        // 基于当前时间设置开始、结束时间
        long currentTimeMillis = System.currentTimeMillis();
        Calendar startCalendar = getTimeScope(currentTimeMillis, startTime);
        Calendar endCalendar = getTimeScope(currentTimeMillis, endTime);
        if (startCalendar == null || endCalendar == null || startCalendar.compareTo(endCalendar) == 0) {
            return false;
        }
        // 如果开始时间大于结束时间，则证明时间范围处于跨天情况(例：22:00 ~ 08:00)，将结束时间前进一天
        if (startCalendar.compareTo(endCalendar) > 0) {
            endCalendar = getCalendar(endCalendar.getTimeInMillis() + A_DAY_IN_MILLIS);
        }
        // startCalendar <= aCalendar <= endCalendar
        return aCalendar.compareTo(startCalendar) >= 0 && aCalendar.compareTo(endCalendar) <= 0;
    }

    /**
     * 基于一个时间戳和时间段构造一个时间
     * @param timestamp
     * @param timeScope
     * @return
     */
    private static Calendar getTimeScope(long timestamp, String timeScope) {
        Date scopeDate = null;
        try {
            scopeDate = parse(HHMMSS, timeScope);
        } catch (Throwable e) {
            logger.error("parse timeScope[{}] error", timeScope, e);
        }
        if (scopeDate == null) {
            return null;
        }
        Calendar stampCal = getCalendar(timestamp);
        Calendar scopeCal = getCalendar(scopeDate.getTime());
        stampCal.set(HOUR_OF_DAY, scopeCal.get(HOUR_OF_DAY));
        stampCal.set(MINUTE, scopeCal.get(MINUTE));
        stampCal.set(SECOND, scopeCal.get(SECOND));
        stampCal.set(MILLISECOND, scopeCal.get(MILLISECOND));
        return stampCal;
    }
    public static String validDate(String date)  {
        String ret = "-1";
        Date date1 = null;
        int format1 = 1;
        int format2 = 1;
        int format3 = 1;
        if (!StringUtils.isEmpty(date)){
            if ("长期".equals(date.trim())){
                ret ="0"; // 0 表示长期
                return ret;
            }
            if(date.length()==6||((date.contains("-")||date.contains("/"))&&date.length()==8)){
                ret = "-1"; // 不合法
                return ret;
            }
            if(date.indexOf("-")>0&&date.indexOf("/")>0){
                ret = "-1"; // 不合法
            }else if (date.indexOf("-")>0&&date.indexOf("/")<0){
                try {
                    synchronized (sdf2){
                        date1 = sdf2.parse(date);
                    }
                } catch (ParseException e) {
                    format2 = 0;
                }
            }else if (date.indexOf("-")<0&&date.indexOf("/")>0){
                try {
                    synchronized (sdf3){
                        date1 = sdf3.parse(date);
                    }
                } catch (ParseException e) {
                    format3 = 0;
                }
            }else{
                try {
                    synchronized (sdf1){
                        date1 = sdf1.parse(date);
                    }
                } catch (ParseException e) {
                    format3 = 0;
                }
            }
        }else{
            ret = "19700101";
        }
        if (format1==0&&format2==0&&format3==0){
            ret = "-1"; // 不合法
        }
        if(date1!=null){
            synchronized (sdf1) {
                ret = sdf1.format(date1);
            }
        }
        return ret;
    }
    public static void test_isInTimeScope() {
        // <下临界值
        System.out.println(isInTimeScope("2018-01-26 02:28:22", "02:28:23", "10:28:23"));
        System.out.println(isInTimeScope("2018-01-26 10:28:22", "10:28:23", "15:28:23"));
        System.out.println(isInTimeScope("2018-01-26 15:28:22", "15:28:23", "22:28:23"));
        System.out.println(isInTimeScope("2018-01-26 22:28:22", "22:28:23", "08:28:23"));
        System.out.println(isInTimeScope("2018-01-26 22:28:22", "22:28:23", "15:28:23"));
        System.out.println("-------------------------------false------------------------------------------");
        // =下临界值
        System.out.println(isInTimeScope("2018-01-26 02:28:23", "02:28:23", "10:28:23"));
        System.out.println(isInTimeScope("2018-01-26 10:28:23", "10:28:23", "15:28:23"));
        System.out.println(isInTimeScope("2018-01-26 15:28:23", "15:28:23", "22:28:23"));
        System.out.println(isInTimeScope("2018-01-26 22:28:23", "22:28:23", "08:28:23"));
        System.out.println(isInTimeScope("2018-01-26 22:28:23", "22:28:23", "15:28:23"));
        System.out.println("-------------------------------true------------------------------------------");
        // <上临界值
        System.out.println(isInTimeScope("2018-01-26 03:28:23", "02:28:23", "10:28:23"));
        System.out.println(isInTimeScope("2018-01-26 11:28:23", "10:28:23", "15:28:23"));
        System.out.println(isInTimeScope("2018-01-26 21:28:23", "15:28:23", "22:28:23"));
        System.out.println(isInTimeScope("2018-01-27 07:28:23", "22:28:23", "08:28:23"));
        System.out.println(isInTimeScope("2018-01-27 10:28:23", "22:28:23", "15:28:23"));
        System.out.println("-------------------------------true------------------------------------------");
        // =上临界值
        System.out.println(isInTimeScope("2018-01-26 10:28:23", "02:28:23", "10:28:23"));
        System.out.println(isInTimeScope("2018-01-26 15:28:23", "10:28:23", "15:28:23"));
        System.out.println(isInTimeScope("2018-01-26 22:28:23", "15:28:23", "22:28:23"));
        System.out.println(isInTimeScope("2018-01-27 08:28:23", "22:28:23", "08:28:23"));
        System.out.println(isInTimeScope("2018-01-27 15:28:23", "22:28:23", "15:28:23"));
        System.out.println("-------------------------------true------------------------------------------");
        // >上临界值
        System.out.println(isInTimeScope("2018-01-26 10:28:24", "02:28:23", "10:28:23"));
        System.out.println(isInTimeScope("2018-01-26 15:28:24", "10:28:23", "15:28:23"));
        System.out.println(isInTimeScope("2018-01-26 22:28:24", "15:28:23", "22:28:23"));
        System.out.println(isInTimeScope("2018-01-27 08:28:24", "22:28:23", "08:28:23"));
        System.out.println(isInTimeScope("2018-01-27 15:28:24", "22:28:23", "15:28:23"));
        System.out.println("-------------------------------false------------------------------------------");
    }
}
