package com.xiongyingqi.common.utils.date;

import com.xiongyingqi.common.utils.Assert;
import com.xiongyingqi.common.utils.string.StringUtils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * 时间工具类
 *
 * @author xiongyingqi 2017-10-13
 */
public abstract class DateUtils {
  /**
   * yyyy-MM-dd HH:mm:ss
   */
  public static final String SP1 = "yyyy-MM-dd HH:mm:ss";

  /**
   * yyyyMMddHHmmss
   */
  public static final String SP2 = "yyyyMMddHHmmss";

  /**
   * yyyy-MM-dd
   */
  public static final String SP3 = "yyyy-MM-dd";

  /**
   * yyyyMMdd
   */
  public static final String SP4 = "yyyyMMdd";

  public static String getNowDate() {
    SimpleDateFormat simpleDateFormat = getDateFormat(SP3);
    return simpleDateFormat.format(new Date());
  }

  public static String getNowDateTime() {
    SimpleDateFormat simpleDateFormat = getDateFormat(SP1);
    return simpleDateFormat.format(new Date());
  }

  public static SimpleDateFormat getDateFormat(String format) {
    Assert.hasText(format);
    return new SimpleDateFormat(format);
  }

  public static long getUnixTime() {
    return System.currentTimeMillis() / 1000;
  }

  /**
   * 将时间以指定格式格式化
   *
   * @param time            待转换时间
   * @param formatStrBefore 转换前时间格式
   * @param formatStrAfter  转换后时间格式
   * @return
   * @throws Exception
   */
  public static String parseTime(String time, String formatStrBefore, String formatStrAfter)
      throws ParseException {
    SimpleDateFormat bfSp = new SimpleDateFormat(formatStrBefore);
    SimpleDateFormat afSp = new SimpleDateFormat(formatStrAfter);
    return afSp.format(bfSp.parse(time));
  }

  /**
   * 比较时间前后
   *
   * @param time1     时间1
   * @param time2     时间2
   * @param formatStr 时间格式
   * @return 时间1比时间2早则返回1 时间1比时间2晚则返回-1 时间1等于时间2则返回0
   * @throws ParseException
   */
  public static int compareTime(String time1, String time2, String formatStr)
      throws ParseException {
    SimpleDateFormat sp = new SimpleDateFormat(formatStr);
    Date date1 = sp.parse(time1);
    Date date2 = sp.parse(time2);
    if (date1.before(date2)) {
      return 1;
    } else if (date1.after(date2)) {
      return -1;
    } else {
      return 0;
    }
  }

  /**
   * 获得指定格式的当前时间
   *
   * @param formatStr 时间格式
   * @return
   */
  public static String getCurrentTime(String formatStr) {
    SimpleDateFormat sp = new SimpleDateFormat(formatStr);
    return sp.format(new Date());
  }

  /**
   * 获取指定格式的某时间,例如1小时前 或者1小时后
   *
   * @param field     例如Calendar.DAY_OF_MONTH
   * @param amount    整数 例如-1
   * @param formatStr 时间格式
   * @return
   */
  public static String getTimeAfter(int field, int amount, String formatStr) {
    Calendar cal = Calendar.getInstance();
    cal.add(field, amount);
    SimpleDateFormat sp = new SimpleDateFormat(formatStr);
    return sp.format(cal.getTime());
  }

  /**
   * 获取当月第一天
   *
   * @param formatStr
   * @return
   */
  public static String getFirstDayOfMonth(String formatStr) {
    SimpleDateFormat sp = new SimpleDateFormat(formatStr);
    Calendar date = Calendar.getInstance();// 今天
    date.set(Calendar.DAY_OF_MONTH, 1);// 设置日期为本月第1天
    date.set(Calendar.HOUR_OF_DAY, 0);// 设置时
    date.set(Calendar.MINUTE, 0);// 设置分
    date.set(Calendar.SECOND, 0);// 设置秒
    return sp.format(date.getTime());
  }

  /**
   * 日期/时间 计算 这个方法只能对yyyy-MM-dd HH:mm:ss 格式的时间进行运算
   * <p>
   * 该方法已经由calculateTime(String time,String formatStr, String addpart, int
   * num) 取代,为做兼容没有删掉
   *
   * @param time    待计算时间
   * @param addpart 可选 Y M D H F S
   * @param num     增加或者减少量(整数)
   * @return
   * @throws Exception
   */
  @Deprecated
  public static String calculateTime(String time, String addpart, int num) throws ParseException {
    DateFormat yyyyMMddHHmmssDateFormat = new SimpleDateFormat(SP1);
    GregorianCalendar cal = new GregorianCalendar();
    cal.setTime(yyyyMMddHHmmssDateFormat.parse(time));
    if (addpart.equalsIgnoreCase("Y")) {
      cal.add(Calendar.YEAR, num);
    } else if (addpart.equalsIgnoreCase("M")) {
      cal.add(Calendar.MONTH, num);
    } else if (addpart.equalsIgnoreCase("D")) {
      cal.add(Calendar.DATE, num);
    } else if (addpart.equalsIgnoreCase("H")) {
      cal.add(Calendar.HOUR, num);
    } else if (addpart.equalsIgnoreCase("F")) {
      cal.add(Calendar.MINUTE, num);
    } else if (addpart.equalsIgnoreCase("S")) {
      cal.add(Calendar.SECOND, num);
    }
    return yyyyMMddHHmmssDateFormat.format(cal.getTime());
  }

  /**
   * 日期/时间 计算
   *
   * @param time      待计算时间
   * @param formatStr 时间格式
   * @param addpart   可选 Y M D H F S
   * @param num       增加或者减少量(整数)
   * @return
   * @throws Exception
   */
  public static String calculateTime(String time, String formatStr, String addpart, int num)
      throws ParseException {
    DateFormat dateFormat = new SimpleDateFormat(formatStr);
    GregorianCalendar cal = new GregorianCalendar();
    cal.setTime(dateFormat.parse(time));
    if (addpart.equalsIgnoreCase("Y")) {
      cal.add(Calendar.YEAR, num);
    } else if (addpart.equalsIgnoreCase("M")) {
      cal.add(Calendar.MONTH, num);
    } else if (addpart.equalsIgnoreCase("D")) {
      cal.add(Calendar.DATE, num);
    } else if (addpart.equalsIgnoreCase("H")) {
      cal.add(Calendar.HOUR, num);
    } else if (addpart.equalsIgnoreCase("F")) {
      cal.add(Calendar.MINUTE, num);
    } else if (addpart.equalsIgnoreCase("S")) {
      cal.add(Calendar.SECOND, num);
    }
    return dateFormat.format(cal.getTime());
  }

  /**
   * 返回两个时间之间的差(毫秒数)
   *
   * @param time1
   * @param time2
   * @param formatStr
   * @return
   * @throws ParseException
   */
  public static long dateDiffer(String time1, String time2, String formatStr)
      throws ParseException {
    SimpleDateFormat sp = new SimpleDateFormat(formatStr);
    Date date1 = sp.parse(time1);
    Date date2 = sp.parse(time2);
    long differ = Math.abs(date1.getTime() - date2.getTime());
    return differ;
  }

  /**
   * 返回指定天数的字符串
   *
   * @param formatString 格式化方式
   * @param days         距今天的天数,可以带符号
   * @return
   */
  public static String getDayString(String formatString, int days) {
    SimpleDateFormat sp = new SimpleDateFormat(formatString);
    return sp.format(getDays(days));
  }

  /**
   * 返回指定天数的字符串
   *
   * @param days 距今天的天数,可以带符号
   * @return
   */
  public static Date getDays(int days) {
    Calendar date = Calendar.getInstance();// 今天
    date.add(Calendar.DATE, days);// 增加或者减少天数
    return date.getTime();
  }

  public static Date getDateAfterDays(Date date, int days) {
    Calendar calendar = Calendar.getInstance();// 今天
    calendar.setTime(date);
    calendar.add(Calendar.DATE, days);// 增加或者减少天数
    return calendar.getTime();
  }

  /**
   * 当月第一天
   *
   * @return yyyy-MM-dd
   */
  public static String getFirstDateStrOfMonth() {
    DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
    return format.format(getFirstDateOfMonth());
  }

  /**
   * 当月第一天
   *
   * @return Date
   */
  public static Date getFirstDateOfMonth() {
    Calendar date = Calendar.getInstance();// 今天
    date.set(Calendar.DAY_OF_MONTH, 1);// 设置日期为本月第1天
    return getZeroTime(date.getTime());
  }

  /**
   * 获取日期的0点时间（即一天的开始）
   *
   * @param date
   * @return
   */
  public static Date getZeroTime(Date date) {
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    calendar.set(Calendar.HOUR_OF_DAY, 0);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);
    return calendar.getTime();
  }

  /**
   * 获取日期的最后秒的时间（即一天的结束时间）
   *
   * @param date
   * @return
   */
  public static Date getLastTime(Date date) {
    Date zeroTime = getZeroTime(date);// 整点时间
    Date dateAfterDays = getDateAfterDays(zeroTime, 1);// 前一天的整点
    long l = dateAfterDays.getTime() - 1;
    return new Date(l);
  }

  public static Date parseDateByFormat(String date, String format) throws ParseException {
    SimpleDateFormat dateFormat = getDateFormat(format);
    return dateFormat.parse(date);
  }

  public static String getDateStringByFormat(Date date, String format) {
    SimpleDateFormat dateFormat = getDateFormat(format);
    return dateFormat.format(date);
  }


  /**
   * 获取日期的年份
   *
   * @return 年份
   */
  public static String getYear(String date) {
    Assert.isTrue(StringUtils.hasText(date) && date.length() >= 4, "解析日期失败！日期长度必须大于3！");
    return date.substring(0, 4);
  }

  /**
   * 获取日期所属的季度（从1开始）。日期的格式必须是"yyyy-MM*"
   *
   * @param date
   * @return 1~4
   */
  public static int getSeason(String date) {
    Assert.isTrue(StringUtils.hasText(date) && date.length() >= 7, "解析季度失败！日期格式必须是：yyyy-MM*");
    String monthStr = date.substring(5, 7);
    Integer month = Integer.parseInt(monthStr);
    Assert.isTrue(month != null && month >= 1, "解析季度失败！日期格式必须是：yyyy-MM*");
    return month / 3 + (month % 3 > 0 ? 1 : 0);
  }

}
