package com.pictc.utils;

import lombok.extern.slf4j.Slf4j;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.Set;

import static java.util.Calendar.DATE;

import java.sql.Time;
import java.sql.Timestamp;


@Slf4j
public class DateUtils {

    public static final String GENERAL = "yyyy-MM-dd";
    
    public static final String FMT_TIME = "HH:mm:ss";
    
    public static final String FMT_OFFSET_DATETIME = "yyyy-MM-dd HH:mm:ssXXX";
    
    public static final String FMT_OFFSET_TIME = "HH:mm:ssXXX";

    public static final String GENERAL_YYYYMMDD = "yyyyMMdd";

    public static final String GENERAL_YYYYMMDDHHMMSS = "yyyyMMddHHmmSS";

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

    public final static DateTimeFormatter FORMATTER_YYYY_MM_DD_HH_MM_SS = DateTimeFormatter.ofPattern(LONG_FORMAT);

    // 针对GMT格式的日期转换格式
    public static final String GMT_DATE_FORMAT = "EEE MMM dd yyyy HH:mm:ss 'GMT'";

    private static final SimpleDateFormat sdf = new SimpleDateFormat(LONG_FORMAT);

    private static final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(GENERAL);
    
	public static final ZoneId zone = ZoneId.of("GMT+8");
    
    private static Set<Class<?>> dates = CollectionUtils.newHashSet();
    
    static {
		dates.add(Date.class);
		dates.add(Time.class);
		dates.add(Timestamp.class);
		dates.add(java.util.Date.class);
    }
    
	public static boolean isDate(Class<?> type) {
		return dates.contains(type);
	}

    public static String formatDate(Date date) {
        if (null == date) {
            return null;
        }
        return sdf.format(date);
    }

    public static Date formatDate2Date(Date date) {
        if (null == date) {
            return null;
        }

        String format = sdf.format(date);
        try {
            return sdf.parse(format);
        } catch (ParseException e) {
            log.error(e.getMessage(), e);
        }
        return null;

    }

    /**
     * 按传入的格式化规则格式化传入的日期
     *
     * @param date       : 传入日期对象
     * @param dateFormat : 格式化规则(如：yyyy-MM-dd,yyyyMMdd等，如果传空或NULL则默认为yyyy-MM-dd)
     * @return String
     * @author 张江立
     */
    public static String formatDate(Date date, String dateFormat) {
        if (null == date) {
            return null;
        }

        if (null == dateFormat || "".equals(dateFormat)) {
            dateFormat = "yyyy-MM-dd";
        }

        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
        String formatDateAfterStr = sdf.format(date);

        return formatDateAfterStr;
    }

    /**
     * 针对格林日期转换为字符串
     *
     * @param datestr：日期字符串，如：datestr = "Tue Jun 05 2018 13:11:11 GMT"
     * @return Date
     */
    public static Date GMTDateToString(String datestr) {
        SimpleDateFormat sdf = new SimpleDateFormat(GMT_DATE_FORMAT, Locale.ENGLISH);
        Date date = null;
        try {
            date = sdf.parse(datestr);
        } catch (ParseException e) {
            log.error(e.getMessage(), e);
        }
        return date;
    }

    /**
     * 传入日期添加天数
     *
     * @param date : 日期对象
     * @param days : 天数
     * @return Date
     */
    public static Date addDays(Date date, int days) {
        if (null == date) {
            return null;
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(DATE, days);
        return calendar.getTime();
    }

    /**
     * 日期字符串转成日期对象
     *
     * @param dateString; 如："2012-12-06"
     * @param dateFormat  :格式化规则(如：yyyy-MM-dd)
     *                    :DateUtils.GENERAL
     *                    :DateUtils.LONG_FORMAT
     * @return Date
     */
    public static Date stringToDate(String dateString, String dateFormat) {
        Date date = null;
        if (null == dateString || "".equals(dateString) || "null".equalsIgnoreCase(dateString) || null == dateFormat || "".equals(dateFormat)) {
            return date;
        }
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
            date = sdf.parse(dateString);
        } catch (ParseException e) {
            log.error(e.getMessage(), e);
            return date;
        }

        return date;
    }


    /**
     * 日期字符串转成日期对象,默认格式: yyyy-MM-dd HH:mm:ss
     *
     * @param dateString
     * @return
     */
    public static Date stringToDate(String dateString) {
        Date date = null;
        if (null == dateString || "".equals(dateString) || "null".equalsIgnoreCase(dateString)) {
            return date;
        }
        try {
            date = sdf.parse(dateString);
        } catch (ParseException e) {
            log.error(e.getMessage(), e);
            return date;
        }
        return date;
    }

    /**
     * 返回昨天
     *
     * @param today
     * @return
     */
    public static Date yesterday(Date today) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(today);
        calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) - 1);
        return calendar.getTime();
    }

    /**
     * 返回明天
     *
     * @param today
     * @return
     */
    public static Date tomorrow(Date today) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(today);
        calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) + 1);
        return calendar.getTime();
    }

    public static final String format(Date date, String pattern) {
    	if(date==null) return null;
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(date);
    }
    
    public static final String format(LocalDate localDate) {
    	return format(localDate, GENERAL);
    }
    
    public static final String format(LocalDate localDate, String pattern) {
    	if(localDate==null) return null;
    	DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(pattern);
    	return localDate.format(dateFormatter);
    }
    
    public static final String format(LocalTime localDate) {
    	return format(localDate,FMT_TIME);
    }
    
    public static final String format(LocalTime localDate,String pattern) {
    	if(localDate==null) return null;
    	DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(pattern);
    	return localDate.format(dateFormatter);
    }
    
    public static final String format(LocalDateTime localDateTime) {
    	return format(localDateTime,LONG_FORMAT);
    }
    
    public static final String format(LocalDateTime localDateTime,String pattern) {
    	if(localDateTime==null) return null;
    	DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(pattern);
    	return localDateTime.format(dateFormatter);
    }
    
    
    public static final String format(OffsetDateTime offsetDateTime) {
    	return format(offsetDateTime,FMT_OFFSET_DATETIME);
    }
    
    public static final String format(OffsetDateTime offsetDateTime,String pattern) {
    	if(offsetDateTime==null) return null;
    	DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(pattern);
    	return offsetDateTime.format(dateFormatter);
    }
    
    public static final String format(OffsetTime offsetTime) {
    	return format(offsetTime,FMT_OFFSET_TIME);
    }
    
    public static final String format(OffsetTime offsetDateTime,String pattern) {
    	if(offsetDateTime==null) return null;
    	DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(pattern);
    	return offsetDateTime.format(dateFormatter);
    }
    


    public static final String format(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }

    public static long getDateTime(String dateStr) {
        Date date = stringToDate(dateStr, "yyyy-MM-dd HH:mm:ss");
        return date.getTime();
    }

    // 取得当前日期(YYYYMMDD)
    public static String getYYYYMMDD() {
        SimpleDateFormat sdf = new SimpleDateFormat(GENERAL_YYYYMMDD);
        return sdf.format(new Date());
    }

    // 取得时间戳(YYYYMMDDHHMMSS)
    public static String getTimeStamp() {
        SimpleDateFormat sdf = new SimpleDateFormat(GENERAL_YYYYMMDDHHMMSS);
        return sdf.format(new Date());
    }

    public static String getYear() {
        Calendar cal = Calendar.getInstance();
        return cal.get(Calendar.YEAR) + "";
    }

    public static String getMonth() {
        Calendar cal = Calendar.getInstance();
        int i = cal.get(Calendar.MONTH) + 1;
        if (i < 10) {
            return "0" + i;
        }
        return i + "";
    }

    public static String getDate() {
        Calendar cal = Calendar.getInstance();
        int i = cal.get(Calendar.DATE);
        if (i < 10) {
            return "0" + i;
        }
        return i + "";
    }

    /**
     * 获取上个月最后一天
     *
     * @return
     */
    public static String getMonthLastDate(String date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        Calendar c = Calendar.getInstance();
        Date parse = new Date();
        // 设置为指定日期
        if (StringUtils.isNotEmpty(date)) {
            date = date.replace("-", "");
            try {
                parse = sdf.parse(date);
            } catch (ParseException e) {
                log.error(e.getMessage(), e);
                return "";
            }
        }
        c.setTime(parse);
        // 指定日期月份减去一
        c.add(Calendar.MONTH, -1);
        // 指定日期月份减去一后的 最大天数
        c.set(Calendar.DATE, c.getActualMaximum(Calendar.DATE));
        // 获取最终的时间
        Date time = c.getTime();
        return sdf.format(time);
    }

    /**
     * 获取yyyy-MM-dd当天
     *
     * @return
     */
    public static String getToday() {
        String today = LocalDate.now().format(fmt);
        return today;
    }

    /**
     * 获取yyyy-MM-dd明天
     *
     * @return
     */
    public static String getTomorrow() {
        String tomorrow = LocalDate.now().plusDays(1).format(fmt);
        return tomorrow;
    }

    /**
     * 设置时间
     *
     * @param date 时间
     * @param hour 小时
     * @param minute 分钟
     * @param second 秒钟
     * @param millisecond 毫秒
     * @return 返回值
     */
    public static Date setDateTime(Date date, Integer hour, Integer minute, Integer second, Integer millisecond) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        calendar.set(Calendar.MILLISECOND, millisecond);
        return calendar.getTime();
    }
    
    public static LocalDateTime toLocalDateTime(String source){
		return toLocalDateTime(source, LONG_FORMAT);
	}
	
	public static LocalDateTime toLocalDateTime(String source,String fmt){
		try {
			return LocalDateTime.parse(source,DateTimeFormatter.ofPattern(fmt));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public static LocalDate toLocalDate(String source){
		return toLocalDate(source, GENERAL);
	}
	
	public static LocalDate toLocalDate(String source,String fmt){
		try {
			return LocalDate.parse(source,DateTimeFormatter.ofPattern(fmt));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public static LocalTime toLocalTime(String source){
		return toLocalTime(source, FMT_TIME);
	}
	
	public static LocalTime toLocalTime(String source,String fmt){
		try {
			return LocalTime.parse(source,DateTimeFormatter.ofPattern(fmt));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public static Timestamp toTimestamp(String source,String fmt){
		try {
			SimpleDateFormat f = new SimpleDateFormat(fmt);
			return new Timestamp(f.parse(source).getTime());
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public static LocalDateTime toLocalDateTime(Date date) {
		return LocalDateTime.ofInstant(new Date(date.getTime()).toInstant(), zone);
	}
	
	public static Date toDate(LocalDateTime ldtime) {
		return Date.from(ldtime.atZone(zone).toInstant());
	}
	
	public static Timestamp toTimestamp(LocalDateTime ldtime) {
		return Timestamp.from(ldtime.atZone(zone).toInstant());
	}

}
