package com.xunmei.common.core.utils.snowId;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import io.netty.util.internal.StringUtil;
import org.apache.commons.lang3.time.DateUtils;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by Tkk on 2018/8/15.
 */
public class DateHelper {

    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private static final SimpleDateFormat dateStrFormat = new SimpleDateFormat("yyyyMMddHHmmss");

    private static final SimpleDateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd");
    private static final SimpleDateFormat HmsFormat = new SimpleDateFormat("HH:mm");

    private final Calendar calendar;

    public DateHelper(final Date date) {
        if (date == null) {
            this.calendar = Calendar.getInstance();
            this.calendar.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        } else {
            this.calendar = Calendar.getInstance();
            this.calendar.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
            this.calendar.setTime(date);
        }
        this.calendar.setFirstDayOfWeek(Calendar.MONDAY);
    }

    public DateHelper() {
        this(new Date());
    }

    public int getYear() {
        return this.calendar.get(Calendar.YEAR);
    }

    public int getMonth() {
        return this.calendar.get(Calendar.MONTH) + 1;
    }

    public int getDay() {
        return this.calendar.get(Calendar.DAY_OF_MONTH);
    }

    public int quarter() {
        return this.getMonth() / 3 + 1;
    }

    private Integer halfYear() {
        Integer half = this.getMonth();
        if (half >= 0 && half <= 6) {
            return 1;
        } else {
            return 2;
        }
    }

    public int getDate() {
        return this.calendar.get(Calendar.DATE);
    }

    public int getHour() {
        return this.calendar.get(Calendar.HOUR_OF_DAY);
    }

    public int getMin() {
        return this.calendar.get(Calendar.MINUTE);
    }

    public void addDays(final int i) {
        this.calendar.add(Calendar.DATE, i);
    }

    public void addMin(final int i) {
        this.calendar.add(Calendar.MINUTE, i);
    }

    public void setSecond(final int i) {
        this.calendar.set(Calendar.SECOND, i);
    }

    public void setMin(final int i) {
        this.calendar.set(Calendar.MINUTE, i);
    }

    public void setHour(final int i) {
        this.calendar.set(Calendar.HOUR_OF_DAY, i);
    }

    public void setDate(final int i) {
        this.calendar.set(Calendar.DAY_OF_MONTH, i);
    }

    public void addMonth(final int i) {
        this.calendar.add(Calendar.MONTH, i);
    }

    public boolean isToday() {
        return DateUtils.isSameDay(this.calendar, Calendar.getInstance());
    }

    public void setMonth(final int month) {
        this.calendar.set(Calendar.MONTH, month);
    }

    public Date getDateTime() {
        this.calendar.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        return this.calendar.getTime();
    }

    public int getWeek() {
        calendar.setMinimalDaysInFirstWeek(6);
        return this.calendar.get(Calendar.WEEK_OF_YEAR);
    }

    public Date monthStart() {
        this.calendar.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        this.calendar.set(Calendar.DAY_OF_MONTH, 1);
        return this.calendar.getTime();
    }

    public Date monthEnd() {
        this.calendar.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        this.calendar.set(Calendar.DAY_OF_MONTH, this.calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        return this.calendar.getTime();
    }

    public Date weekStart() {
        // 设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一
        this.calendar.setFirstDayOfWeek(Calendar.MONDAY);
        // 获得当前日期是一个星期的第几天
        int dayWeek = this.calendar.get(Calendar.DAY_OF_WEEK);
        // 根据日历的规则，给当前日期减去星期几与一个星期第一天的差值
        this.calendar.add(Calendar.DATE, this.calendar.getFirstDayOfWeek() - dayWeek);
        return this.calendar.getTime();
    }

    public Date weekEnd() {
        // 设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一
        this.calendar.setFirstDayOfWeek(Calendar.MONDAY);
        // 获得当前日期是一个星期的第几天
        int dayWeek = this.calendar.get(Calendar.DAY_OF_WEEK);
        // 根据日历的规则，给当前日期减去星期几与一个星期第一天的差值
        this.calendar.add(Calendar.DATE, this.calendar.getFirstDayOfWeek() - dayWeek);
        this.calendar.add(Calendar.DATE, 6);
        return this.calendar.getTime();
    }

    public static Date getThisWeekMonday(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        // 获得当前日期是一个星期的第几天 使用cal.get(Calendar.DAY_OF_WEEK);
        //获取的数表示的是每个星期的第几天，不能改变，其中星期日为第一天
        // 如果是星期日则获取天数时获取到的数字为1 在后面进行相减的时候出错
        int dayWeek = cal.get(Calendar.DAY_OF_WEEK);
        if (1 == dayWeek) {
            cal.add(Calendar.DAY_OF_MONTH, -1);
        }
        // 设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        // 获得当前日期是一个星期的第几天
        int day = cal.get(Calendar.DAY_OF_WEEK);
        // 根据日历的规则，给当前日期减去星期几与一个星期第一天的差值
        //  cal.getFirstDayOfWeek()根据前面的设置 来动态的改变此值
        cal.add(Calendar.DATE, cal.getFirstDayOfWeek() - day);
        return cal.getTime();
    }

    public Date quarterStart() {
        Integer year = this.calendar.get(Calendar.YEAR);
        int month = this.calendar.get(Calendar.MONTH) + 1;
        int quarter = 0;
        if (month >= 1 && month <= 3) {
            quarter = 1;
        } else if (month >= 4 && month <= 6) {
            quarter = 2;
        } else if (month >= 7 && month <= 9) {
            quarter = 3;
        } else {
            quarter = 4;
        }
        return this.getFirstDayOfQuarter(year, quarter);
    }

    public Date quarterEnd() {
        Integer year = this.calendar.get(Calendar.YEAR);
        int month = this.calendar.get(Calendar.MONTH) + 1;
        int quarter = 0;
        if (month >= 1 && month <= 3) {
            quarter = 1;
        } else if (month >= 4 && month <= 6) {
            quarter = 2;
        } else if (month >= 7 && month <= 9) {
            quarter = 3;
        } else {
            quarter = 4;
        }
        return this.getLastDayOfQuarter(year, quarter);
    }

    public Date halfyearStart() {
        Integer year = this.calendar.get(Calendar.YEAR);
        int month = this.calendar.get(Calendar.MONTH) + 1;
        if (month >= 1 && month <= 6) {
            return getFirstDayOfMonth(year, 1);
        } else {
            return getFirstDayOfMonth(year, 7);
        }
    }

    public Date halfyearEnd() {
        Integer year = this.calendar.get(Calendar.YEAR);
        int month = this.calendar.get(Calendar.MONTH) + 1;
        if (month >= 1 && month <= 6) {
            return getLastDayOfMonth(year, 6);
        } else {
            return getLastDayOfMonth(year, 12);
        }
    }

    public Date yearStart() {
        Integer year = this.calendar.get(Calendar.YEAR);
        return getFirstDayOfMonth(year, 1);
    }

    public Date yearEnd() {
        Integer year = this.calendar.get(Calendar.YEAR);
        return getLastDayOfMonth(year, 12);
    }

    public static String toStr(Date date) {
        if (date == null) {
            return StringUtil.EMPTY_STRING;
        }
        return dateFormat.format(date);
    }

    public static String toStrWithoutHms(Date date) {
        if (date == null) {
            return StringUtil.EMPTY_STRING;
        }
        return dayFormat.format(date);
    }
    public static String toStrWithoutYmd(Date date) {
        if (date == null) {
            return StringUtil.EMPTY_STRING;
        }
        return HmsFormat.format(date);
    }

    /**
     * 获取某一周的第一天
     *
     * @param year
     * @param week
     * @return
     */
    public static Date getLastDayOfWeek(final int year, final int week) {
        final Calendar cal = Calendar.getInstance();
        //设置年份
        cal.set(Calendar.YEAR, year);
        //设置周
        cal.set(Calendar.WEEK_OF_YEAR, week);
        //设置该周第一天为星期一
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        //设置最后一天是星期日
        cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek() + 6); // Sunday
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 1);
        return cal.getTime();
    }

    /**
     * 获取某周第一天
     *
     * @param year
     * @param week
     * @return
     */
    public static Date getFirstDayOfWeek(final int year, final int week) {
        final Calendar cal = Calendar.getInstance();
        //设置年份
        cal.set(Calendar.YEAR, year);
        //设置周
        cal.set(Calendar.WEEK_OF_YEAR, week);
        //设置该周第一天为星期一
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        //设置最后一天是星期日
        cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 1);
        return cal.getTime();
    }

    /**
     * 获取某一月的第一天
     *
     * @param year
     * @param month
     * @return
     */
    public static Date getFirstDayOfMonth(final int year, final int month) {
        final Calendar cal = Calendar.getInstance();
        cal.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        //设置年份
        cal.set(Calendar.YEAR, year);
        //设置月份
        cal.set(Calendar.MONTH, month - 1);
        //设置日历中月份的最大天数
        cal.set(Calendar.DAY_OF_MONTH, 1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 1);
        return cal.getTime();
    }

    /**
     * 获取某一月的第一天
     *
     * @param year
     * @param month
     * @return
     */
    public static Date getLastDayOfMonth(final int year, final int month) {
        final Calendar cal = Calendar.getInstance();
        cal.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        //设置年份
        cal.set(Calendar.YEAR, year);
        //设置月份
        cal.set(Calendar.MONTH, month - 1);
        //获取某月最大天数
        final int lastDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
        //设置日历中月份的最大天数
        cal.set(Calendar.DAY_OF_MONTH, lastDay);
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        return cal.getTime();
    }


    /**
     * 获取某个季度的最后一天
     *
     * @param year
     * @param quarter
     * @return
     */
    public static Date getLastDayOfQuarter(final Integer year, final Integer quarter) {
        switch (quarter) {
            case 1:
                return getLastDayOfMonth(year, 3);
            case 2:
                return getLastDayOfMonth(year, 6);
            case 3:
                return getLastDayOfMonth(year, 9);
            default:
                return getLastDayOfMonth(year, 12);
        }
    }

    /**
     * 获取某个季度的第一天
     *
     * @param year
     * @param quarter
     * @return
     */
    public static Date getFirstDayOfQuarter(final Integer year, final Integer quarter) {
        switch (quarter) {
            case 1:
                return getFirstDayOfMonth(year, 1);
            case 2:
                return getFirstDayOfMonth(year, 4);
            case 3:
                return getFirstDayOfMonth(year, 7);
            default:
                return getFirstDayOfMonth(year, 10);
        }
    }

    /**
     * 获取某个半年的最后一天
     *
     * @param year
     * @param halfyear
     * @return
     */
    public static Date getLastDayOfHalfyear(final Integer year, final Integer halfyear) {
        switch (halfyear) {
            case 1:
                return getLastDayOfMonth(year, 6);
            default:
                return getLastDayOfMonth(year, 12);
        }
    }

    /**
     * 获取某个半年的第一天
     *
     * @param year
     * @param halfyear
     * @return
     */
    public static Date getFirstDayOfHalfyear(final Integer year, final Integer halfyear) {
        switch (halfyear) {
            case 1:
                return getFirstDayOfMonth(year, 1);
            default:
                return getFirstDayOfMonth(year, 7);
        }
    }

    /**
     * 获取某年的最后一天
     *
     * @param year
     * @return
     */
    public static Date getLastDayOfYear(final Integer year) {
        return getLastDayOfMonth(year, 12);
    }

    /**
     * 获取某年的最后一天
     *
     * @param year
     * @return
     */
    public static Date getFirstDayOfYear(final Integer year) {
        return getFirstDayOfMonth(year, 1);
    }

    /**
     * @param date
     */
    public static List<DateTime> fromMonthStart(final Date date) {
        DateHelper dateHelper = new DateHelper(date);
        dateHelper.setHour(23);
        dateHelper.setMin(59);
        dateHelper.setDate(1);
        final Date startDate = dateHelper.getDateTime();

        dateHelper = new DateHelper(date);
        dateHelper.setHour(23);
        final Date endDate = dateHelper.getDateTime();
        return DateUtil.rangeToList(startDate, endDate, DateField.DAY_OF_MONTH);
    }

    public int getQuarter() {
        final int m = this.getMonth();
        if (m >= 1 && m <= 3) {
            return 1;
        } else if (m >= 4 && m <= 6) {
            return 2;
        } else if (m >= 7 && m <= 9) {
            return 3;
        } else {
            return 4;
        }
    }

    public int getHalfyear() {
        final int m = this.getMonth();
        if (m >= 1 && m <= 6) {
            return 1;
        } else {
            return 2;
        }
    }

    public void setYear(final Integer ys) {
        this.calendar.set(Calendar.YEAR, ys);
    }

    public static String getDateString(Date date) {
        dateStrFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        return dateStrFormat.format(date);
    }

    public static String getDayString(Date date) {
        dayFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        return dayFormat.format(date);
    }

    public static Date getDate(Date date) {
        dayFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        Date temp = null;
        try {
            temp = dayFormat.parse(dayFormat.format(date));
        } catch (Exception e) {
            temp = date;
        }
        return temp;
    }


    public static Map<String, Date> getStartAndEnd(DateHelper dateHelper, Integer planCycle) {
        if (planCycle == null) {
            return new HashMap<>();
        }
        Map<String, Date> map = new HashMap<>();
        Date startTime = null;
        Date endTime = null;
        final Date dateTime = dateHelper.getDateTime();
        switch (planCycle) {
            case 0:
                //每天
                startTime = DateUtil.beginOfDay(dateTime);
                endTime = DateUtil.endOfDay(dateTime);
                break;
            case 1:
                //每周
                startTime = DateUtil.beginOfWeek(dateTime);
                endTime = DateUtil.endOfWeek(dateTime);
                break;
            case 2:
                //每月
                startTime = DateUtil.beginOfMonth(dateTime);
                endTime = DateUtil.endOfMonth(dateTime);
                break;
            case 3:
                //每季
                startTime = DateHelper.getFirstDayOfQuarter(DateUtil.year(dateTime), DateUtil.quarter(dateTime));
                endTime = DateHelper.getLastDayOfQuarter(DateUtil.year(dateTime), DateUtil.quarter(dateTime));
                break;
            case 4:
                //每半年
                startTime = DateHelper.getFirstDayOfHalfyear(DateUtil.year(dateTime), DateUtil.quarter(dateTime));
                endTime = DateHelper.getLastDayOfHalfyear(DateUtil.year(dateTime), DateUtil.quarter(dateTime));
                break;
            //每年
            case 5:
                startTime = DateUtil.beginOfYear(dateTime);
                endTime = DateUtil.endOfYear(dateTime);
                break;
            default:
                break;
        }
        map.put("start", getPreciseTime(startTime));
        map.put("end", getPreciseTime(endTime));
        return map;
    }


    public static Date getPreciseTime(Date date) {
        // 日历对象
        Calendar c = Calendar.getInstance();
        // 设置时间
        c.setTime(date);
        // 设置毫秒值为0
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }


    public static String getUpcastNumber(int number) {
        if (number == 1) {
            return "一";
        }
        if (number == 2) {
            return "二";
        }
        if (number == 3) {
            return "三";
        }
        if (number == 4) {
            return "四";
        }
        if (number == 5) {
            return "五";
        }
        if (number == 6) {
            return "六";
        }
        if (number == 7) {
            return "天";
        }
        return StringUtil.EMPTY_STRING;
    }

    public static int getMonth(DateTime date) {
        final Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        return instance.get(Calendar.MONTH) + 1;
    }
}
