// Author: fengshengxiong
// Date: 2024/5/11
// Description: 日期工具类

/// 一些常用格式参照。可以自定义格式，例如：'yyyy/MM/dd HH:mm:ss'，'yyyy/M/d HH:mm:ss'。
/// 格式要求
/// year -> yyyy/yy   month -> MM/M    day -> dd/d
/// hour -> HH/H      minute -> mm/m   second -> ss/s
class DateFormats {
  static String full = 'yyyy-MM-dd HH:mm:ss';
  static String yMoDHM = 'yyyy-MM-dd HH:mm';
  static String yMoD = 'yyyy-MM-dd';
  static String yMD = 'yyyyMMdd';
  static String yMo = 'yyyy-MM';
  static String moD = 'MM-dd';
  static String moDHM = 'MM-dd HH:mm';
  static String hMS = 'HH:mm:ss';
  static String hM = 'HH:mm';

  static String zhFull = 'yyyy年MM月dd日 HH时mm分ss秒';
  static String zhYMoDHM = 'yyyy年MM月dd日 HH时mm分';
  static String zhYMoD = 'yyyy年MM月dd日';
  static String zhYMo = 'yyyy年MM月';
  static String zhMoD = 'MM月dd日';
  static String zhMoDHM = 'MM月dd日 HH时mm分';
  static String zhHMS = 'HH时mm分ss秒';
  static String zhHM = 'HH时mm分';
}

class DateUtil {
  /// 月->天数.
  static Map<int, int> monthDay = {
    1: 31,
    2: 28,
    3: 31,
    4: 30,
    5: 31,
    6: 30,
    7: 31,
    8: 31,
    9: 30,
    10: 31,
    11: 30,
    12: 31,
  };

  /// 获取当前时间，默认格式(yyyy-MM-dd HH:mm:ss)
  static String getNowTimeStr({String? format}) {
    return formatDate(DateTime.now(), format: format);
  }

  /// 获取当前时间戳
  static int getNowTimestamp() {
    return DateTime.now().millisecondsSinceEpoch;
  }

  /// 以毫秒为单位格式化日期
  static String formatDateMs(int ms, {bool isUtc = false, String? format}) {
    return formatDate(getDateTimeByMs(ms, isUtc: isUtc), format: format);
  }

  /// 毫秒 转 DateTime
  static DateTime getDateTimeByMs(int ms, {bool isUtc = false}) {
    return DateTime.fromMillisecondsSinceEpoch(ms, isUtc: isUtc);
  }

  /// 日期str 转 毫秒
  static int? getDateMsByTimeStr(String dateStr, {bool? isUtc}) {
    DateTime? dateTime = getDateTime(dateStr, isUtc: isUtc);
    return dateTime?.millisecondsSinceEpoch;
  }

  /// 按日期str格式化日期
  static String formatDateStr(String dateStr, {bool? isUtc, String? format}) {
    return formatDate(getDateTime(dateStr, isUtc: isUtc), format: format);
  }

  /// 日期str 转 DateTime
  static DateTime? getDateTime(String dateStr, {bool? isUtc}) {
    DateTime? dateTime = DateTime.tryParse(dateStr);
    if (isUtc != null) {
      if (isUtc) {
        dateTime = dateTime?.toUtc();
      } else {
        dateTime = dateTime?.toLocal();
      }
    }
    return dateTime;
  }

  /// 按DateTime格式化日期
  /// format 转换格式(已提供常用格式 DateFormats，可以自定义格式：'yyyy/MM/dd HH:mm:ss')
  /// 格式要求
  /// year -> yyyy/yy   month -> MM/M    day -> dd/d
  /// hour -> HH/H      minute -> mm/m   second -> ss/s
  static String formatDate(DateTime? dateTime, {String? format}) {
    if (dateTime == null) return '';
    format = format ?? DateFormats.full;
    if (format.contains('yy')) {
      String year = dateTime.year.toString();
      if (format.contains('yyyy')) {
        format = format.replaceAll('yyyy', year);
      } else {
        format = format.replaceAll(
            'yy', year.substring(year.length - 2, year.length));
      }
    }

    format = _comFormat(dateTime.month, format, 'M', 'MM');
    format = _comFormat(dateTime.day, format, 'd', 'dd');
    format = _comFormat(dateTime.hour, format, 'H', 'HH');
    format = _comFormat(dateTime.minute, format, 'm', 'mm');
    format = _comFormat(dateTime.second, format, 's', 'ss');
    format = _comFormat(dateTime.millisecond, format, 'S', 'SSS');

    return format;
  }

  static String _comFormat(int value, String format, String single, String full) {
    if (format.contains(single)) {
      if (format.contains(full)) {
        format = format.replaceAll(full, value < 10 ? '0$value' : value.toString());
      } else {
        format = format.replaceAll(single, value.toString());
      }
    }
    return format;
  }

  /// 工作日
  /// dateTime
  /// isUtc
  /// languageCode zh or en
  /// short
  static String getWeekday(DateTime? dateTime, {String languageCode = 'zh', bool short = false}) {
    if (dateTime == null) return '';
    String weekday = '';
    switch (dateTime.weekday) {
      case 1:
        weekday = languageCode == 'zh' ? '星期一' : 'Monday';
        break;
      case 2:
        weekday = languageCode == 'zh' ? '星期二' : 'Tuesday';
        break;
      case 3:
        weekday = languageCode == 'zh' ? '星期三' : 'Wednesday';
        break;
      case 4:
        weekday = languageCode == 'zh' ? '星期四' : 'Thursday';
        break;
      case 5:
        weekday = languageCode == 'zh' ? '星期五' : 'Friday';
        break;
      case 6:
        weekday = languageCode == 'zh' ? '星期六' : 'Saturday';
        break;
      case 7:
        weekday = languageCode == 'zh' ? '星期日' : 'Sunday';
        break;
      default:
        break;
    }
    return languageCode == 'zh'
        ? (short ? weekday.replaceAll('星期', '周') : weekday)
        : weekday.substring(0, short ? 3 : weekday.length);
  }

  /// 以毫秒计算工作日
  static String getWeekdayByMs(int milliseconds, {bool isUtc = false, String languageCode = 'zh', bool short = false}) {
    DateTime dateTime = getDateTimeByMs(milliseconds, isUtc: isUtc);
    return getWeekday(dateTime, languageCode: languageCode, short: short);
  }

  /// 在今年的第几天
  static int getDayOfYear(DateTime dateTime) {
    int year = dateTime.year;
    int month = dateTime.month;
    int days = dateTime.day;
    for (int i = 1; i < month; i++) {
      days = days + monthDay[i]!;
    }
    if (isLeapYearByYear(year) && month > 2) {
      days = days + 1;
    }
    return days;
  }

  /// 在今年的第几天
  static int getDayOfYearByMs(int ms, {bool isUtc = false}) {
    return getDayOfYear(DateTime.fromMillisecondsSinceEpoch(ms, isUtc: isUtc));
  }

  /// 是否是当天
  static bool isToday(int? milliseconds, {bool isUtc = false, int? locMs}) {
    if (milliseconds == null || milliseconds == 0) return false;
    DateTime old =
    DateTime.fromMillisecondsSinceEpoch(milliseconds, isUtc: isUtc);
    DateTime now;
    if (locMs != null) {
      now = DateUtil.getDateTimeByMs(locMs);
    } else {
      now = isUtc ? DateTime.now().toUtc() : DateTime.now().toLocal();
    }
    return old.year == now.year && old.month == now.month && old.day == now.day;
  }

  /// 是否是昨天.
  static bool isYesterday(DateTime dateTime, DateTime locDateTime) {
    if (yearIsEqual(dateTime, locDateTime)) {
      int spDay = getDayOfYear(locDateTime) - getDayOfYear(dateTime);
      return spDay == 1;
    } else {
      return ((locDateTime.year - dateTime.year == 1) &&
          dateTime.month == 12 &&
          locDateTime.month == 1 &&
          dateTime.day == 31 &&
          locDateTime.day == 1);
    }
  }

  /// 是否是昨天
  static bool isYesterdayByMs(int ms, int locMs) {
    return isYesterday(DateTime.fromMillisecondsSinceEpoch(ms),
        DateTime.fromMillisecondsSinceEpoch(locMs));
  }

  /// 是否是本周
  static bool isWeek(int? ms, {bool isUtc = false, int? locMs}) {
    if (ms == null || ms <= 0) {
      return false;
    }
    DateTime oldT = DateTime.fromMillisecondsSinceEpoch(ms, isUtc: isUtc);
    DateTime nowT;
    if (locMs != null) {
      nowT = DateUtil.getDateTimeByMs(locMs, isUtc: isUtc);
    } else {
      nowT = isUtc ? DateTime.now().toUtc() : DateTime.now().toLocal();
    }

    DateTime old =
    nowT.millisecondsSinceEpoch > oldT.millisecondsSinceEpoch ? oldT : nowT;
    DateTime now =
    nowT.millisecondsSinceEpoch > oldT.millisecondsSinceEpoch ? nowT : oldT;
    return (now.weekday >= old.weekday) &&
        (now.millisecondsSinceEpoch - old.millisecondsSinceEpoch <=
            7 * 24 * 60 * 60 * 1000);
  }

  /// 是否同年
  static bool yearIsEqual(DateTime dateTime, DateTime locDateTime) {
    return dateTime.year == locDateTime.year;
  }

  /// 是否同年
  static bool yearIsEqualByMs(int ms, int locMs) {
    return yearIsEqual(DateTime.fromMillisecondsSinceEpoch(ms),
        DateTime.fromMillisecondsSinceEpoch(locMs));
  }

  /// 是否是闰年
  static bool isLeapYear(DateTime dateTime) {
    return isLeapYearByYear(dateTime.year);
  }

  /// 是否是闰年
  static bool isLeapYearByYear(int year) {
    return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
  }

  /// 判断两个 DateTime 是否是同一天
  static bool isSameDay(String date1, String date2) {
    final dateTime1 = getDateTime(date1);
    final dateTime2 = getDateTime(date2);
    if(dateTime1?.year == dateTime2?.year && dateTime1?.month == dateTime2?.month && dateTime1?.day == dateTime2?.day) {
      return true;
    }
    return false;
  }

  /// 如果如果当前月是12，下月年份需要+1
  static int getNextMonthToYear() {
    DateTime dateTime = DateTime.now();
    if(dateTime.month == 12) {
      return dateTime.year + 1;
    }
    return dateTime.year;
  }

  /// 获取当前下月
  static int getNextMonth() {
    DateTime dateTime = DateTime.now();
    if (dateTime.month == 12) {
      return 1;
    }
    return dateTime.month + 1;
  }

  /// 获取当前日期往前推七天的日期
  static String getSevenDaysAgo() {
    // 获取当前日期
    DateTime now = DateTime.now();

    // 计算往前推七天的日期
    DateTime sevenDaysAgo = now.subtract(const Duration(days: 7));
    return formatDate(sevenDaysAgo, format: DateFormats.yMD);
  }

  /// 格式化播放时间
  static String playDuration(Duration duration) {
    String twoDigits(int n) => n.toString().padLeft(2, '0');
    final minutes = twoDigits(duration.inMinutes.remainder(60));
    final seconds = twoDigits(duration.inSeconds.remainder(60));
    return '$minutes:$seconds';
  }
}