"use strict";

exports.__esModule = true;
exports.RANGE_CHECK_RESULT = void 0;
exports.checkDateRange = checkDateRange;
exports.cloneDate = cloneDate;
exports.getDateNum = getDateNum;
exports.getNearestDate = getNearestDate;
exports.getRangeDate = getRangeDate;
exports.getRealRange = getRealRange;
exports.isTypeSame = isTypeSame;
exports.isValidDate = isValidDate;
exports.toDate = toDate;
exports.toDay = toDay;
exports.toValidDate = toValidDate;

var _dayjs = _interopRequireDefault(require("dayjs"));

var _fp = require("./fp");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function isDate(obj) {
  return typeof obj === 'object' && obj instanceof Date;
}

function isValidDate(obj) {
  return isDate(obj) && !isNaN(obj.getTime());
}

function toValidDate(from, defaultDate) {
  var res = toDate(from);
  return isValidDate(res) ? res : defaultDate || new Date();
}

function toDate(from) {
  if ((0, _fp.isInvalidValue)(from)) {
    return undefined;
  }

  if (isDate(from)) {
    return from;
  }

  if (typeof from === 'object' && typeof from.toDate === 'function') {
    var d = from.toDate();

    if (isDate(d)) {
      return d;
    }
  }

  return toDay(from).toDate();
}

function toDay(from) {
  return (0, _dayjs.default)(from);
}

function cloneDate(d) {
  return new Date(d.getTime());
}

function getDateNum(type, d) {
  switch (type) {
    case 'y':
      return d.getFullYear();

    case 'm':
      return d.getMonth();

    case 'd':
      return d.getDate();

    case 'h':
      return d.getHours();

    case 'i':
      return d.getMinutes();

    case 's':
      return d.getSeconds();
  }
}

function isTypeSame(type, d1, d2) {
  return getDateNum(type, d1) === getDateNum(type, d2);
}

var RANGE_CHECK_RESULT;
exports.RANGE_CHECK_RESULT = RANGE_CHECK_RESULT;

(function (RANGE_CHECK_RESULT) {
  RANGE_CHECK_RESULT[RANGE_CHECK_RESULT["IN_RANGE"] = 0] = "IN_RANGE";
  RANGE_CHECK_RESULT[RANGE_CHECK_RESULT["SMALL_THAN_HOUR"] = 1] = "SMALL_THAN_HOUR";
  RANGE_CHECK_RESULT[RANGE_CHECK_RESULT["BIGGER_THAN_HOUR"] = 2] = "BIGGER_THAN_HOUR";
  RANGE_CHECK_RESULT[RANGE_CHECK_RESULT["SMALL_THAN_MIN"] = 3] = "SMALL_THAN_MIN";
  RANGE_CHECK_RESULT[RANGE_CHECK_RESULT["BIGGER_THAN_MIN"] = 4] = "BIGGER_THAN_MIN";
  RANGE_CHECK_RESULT[RANGE_CHECK_RESULT["SMALL_THAN_SEC"] = 5] = "SMALL_THAN_SEC";
  RANGE_CHECK_RESULT[RANGE_CHECK_RESULT["BIGGER_THAN_SEC"] = 6] = "BIGGER_THAN_SEC";
  RANGE_CHECK_RESULT[RANGE_CHECK_RESULT["SMALL_THAN_YEAR"] = 7] = "SMALL_THAN_YEAR";
  RANGE_CHECK_RESULT[RANGE_CHECK_RESULT["BIGGER_THAN_YEAR"] = 8] = "BIGGER_THAN_YEAR";
  RANGE_CHECK_RESULT[RANGE_CHECK_RESULT["SMALL_THAN_MONTH"] = 9] = "SMALL_THAN_MONTH";
  RANGE_CHECK_RESULT[RANGE_CHECK_RESULT["BIGGER_THAN_MONTH"] = 10] = "BIGGER_THAN_MONTH";
  RANGE_CHECK_RESULT[RANGE_CHECK_RESULT["SMALL_THAN_DAY"] = 11] = "SMALL_THAN_DAY";
  RANGE_CHECK_RESULT[RANGE_CHECK_RESULT["BIGGER_THAN_DAY"] = 12] = "BIGGER_THAN_DAY";
})(RANGE_CHECK_RESULT || (exports.RANGE_CHECK_RESULT = RANGE_CHECK_RESULT = {}));

var TIME_PRE_CHECK;

(function (TIME_PRE_CHECK) {
  TIME_PRE_CHECK[TIME_PRE_CHECK["NONE"] = 0] = "NONE";
  TIME_PRE_CHECK[TIME_PRE_CHECK["SKIP"] = 1] = "SKIP";
  TIME_PRE_CHECK[TIME_PRE_CHECK["USE_START"] = 2] = "USE_START";
  TIME_PRE_CHECK[TIME_PRE_CHECK["USE_END"] = 3] = "USE_END";
})(TIME_PRE_CHECK || (TIME_PRE_CHECK = {}));

function checkDateRange(d, options, validRange) {
  if (!validRange) {
    return RANGE_CHECK_RESULT.IN_RANGE;
  }

  var startDate = validRange[0],
      endDate = validRange[1];
  var isCheckDate = TIME_PRE_CHECK.NONE;

  if (options.date) {
    var _options$date = options.date,
        hasYear = _options$date.hasYear,
        hasMonth = _options$date.hasMonth,
        hasDay = _options$date.hasDay;
    isCheckDate = TIME_PRE_CHECK.SKIP;

    if (hasYear) {
      if (getDateNum('y', startDate) > getDateNum('y', d)) {
        return RANGE_CHECK_RESULT.BIGGER_THAN_YEAR;
      }

      if (getDateNum('y', endDate) < getDateNum('d', d)) {
        return RANGE_CHECK_RESULT.SMALL_THAN_YEAR;
      }
    }

    var isStartYear = isTypeSame('y', d, startDate);
    var isEndYear = isTypeSame('y', d, endDate);

    if ((isStartYear || isEndYear) && hasMonth) {
      if (isStartYear && getDateNum('m', startDate) > getDateNum('m', d)) {
        return RANGE_CHECK_RESULT.BIGGER_THAN_MONTH;
      }

      if (isEndYear && getDateNum('m', endDate) < getDateNum('m', d)) {
        return RANGE_CHECK_RESULT.SMALL_THAN_MONTH;
      }
    }

    var isStartMonth = isStartYear && isTypeSame('m', d, startDate);
    var isEndMonth = isEndYear && isTypeSame('m', d, endDate);

    if (isStartMonth || isEndMonth) {
      if (hasDay) {
        if (isStartMonth && getDateNum('d', startDate) > getDateNum('d', d)) {
          return RANGE_CHECK_RESULT.BIGGER_THAN_DAY;
        }

        if (isEndMonth && getDateNum('d', endDate) < getDateNum('d', d)) {
          return RANGE_CHECK_RESULT.SMALL_THAN_DAY;
        }

        if (isEndMonth && isTypeSame('d', endDate, d)) {
          isCheckDate = TIME_PRE_CHECK.USE_END;
        }

        if (isStartMonth && isTypeSame('d', startDate, d)) {
          isCheckDate = TIME_PRE_CHECK.USE_START;
        }
      } else {
        isCheckDate = isStartMonth ? TIME_PRE_CHECK.USE_START : TIME_PRE_CHECK.USE_END;
      }
    }
  }

  if (options.time && isCheckDate !== TIME_PRE_CHECK.SKIP) {
    var _options$time = options.time,
        hasHour = _options$time.hasHour,
        hasMinute = _options$time.hasMinute,
        hasSecond = _options$time.hasSecond;

    if (hasHour) {
      if (isCheckDate !== TIME_PRE_CHECK.USE_END && getDateNum('h', startDate) > getDateNum('h', d)) {
        return RANGE_CHECK_RESULT.BIGGER_THAN_HOUR;
      }

      if (isCheckDate !== TIME_PRE_CHECK.USE_START && getDateNum('h', endDate) < getDateNum('h', d)) {
        return RANGE_CHECK_RESULT.SMALL_THAN_HOUR;
      }
    }

    var isStartHour = isTypeSame('h', d, startDate);
    var isEndHour = isTypeSame('h', d, endDate);

    if ((isStartHour || isEndHour) && hasMinute) {
      if (isStartHour && isCheckDate !== TIME_PRE_CHECK.USE_END && getDateNum('i', startDate) > getDateNum('i', d)) {
        return RANGE_CHECK_RESULT.BIGGER_THAN_MIN;
      }

      if (isEndHour && isCheckDate !== TIME_PRE_CHECK.USE_START && getDateNum('i', endDate) < getDateNum('i', d)) {
        return RANGE_CHECK_RESULT.SMALL_THAN_MIN;
      }
    }

    var isStartMinutes = isStartHour && isTypeSame('i', d, startDate);
    var isEndMinutes = isEndHour && isTypeSame('i', d, endDate);

    if ((isStartMinutes || isEndMinutes) && hasSecond) {
      if (isStartMinutes && isCheckDate !== TIME_PRE_CHECK.USE_END && getDateNum('s', startDate) > getDateNum('s', d)) {
        return RANGE_CHECK_RESULT.BIGGER_THAN_SEC;
      }

      if (isEndMinutes && isCheckDate !== TIME_PRE_CHECK.USE_START && getDateNum('s', endDate) < getDateNum('s', d)) {
        return RANGE_CHECK_RESULT.SMALL_THAN_SEC;
      }
    }
  }

  return RANGE_CHECK_RESULT.IN_RANGE;
}

function getRangeDate(d, options, validRange) {
  if (!validRange) {
    return d;
  }

  var startDate = validRange[0],
      endDate = validRange[1];
  var newDate;

  switch (checkDateRange(d, options, validRange)) {
    case RANGE_CHECK_RESULT.IN_RANGE:
      return d;

    case RANGE_CHECK_RESULT.SMALL_THAN_YEAR:
    case RANGE_CHECK_RESULT.SMALL_THAN_MONTH:
    case RANGE_CHECK_RESULT.SMALL_THAN_DAY:
    case RANGE_CHECK_RESULT.SMALL_THAN_HOUR:
    case RANGE_CHECK_RESULT.SMALL_THAN_MIN:
    case RANGE_CHECK_RESULT.SMALL_THAN_SEC:
      newDate = cloneDate(endDate);
      break;

    case RANGE_CHECK_RESULT.BIGGER_THAN_YEAR:
    case RANGE_CHECK_RESULT.BIGGER_THAN_MONTH:
    case RANGE_CHECK_RESULT.BIGGER_THAN_DAY:
    case RANGE_CHECK_RESULT.BIGGER_THAN_HOUR:
    case RANGE_CHECK_RESULT.BIGGER_THAN_MIN:
    case RANGE_CHECK_RESULT.BIGGER_THAN_SEC:
      newDate = cloneDate(startDate);
      break;
  }

  if (options.date) {
    var _options$date2 = options.date,
        hasMonth = _options$date2.hasMonth,
        hasDay = _options$date2.hasDay;

    if (!hasDay) {
      newDate.setDate(1);
    }

    if (!hasMonth) {
      newDate.setMonth(0);

      if (newDate.getMonth() !== 0) {
        newDate.setMonth(0);
      }
    }
  }

  if (options.time) {
    var _options$time2 = options.time,
        hasHour = _options$time2.hasHour,
        hasMinute = _options$time2.hasMinute,
        hasSecond = _options$time2.hasSecond;

    if (!hasHour) {
      newDate.setHours(0);
    }

    if (!hasMinute) {
      newDate.setMinutes(0);
    }

    if (!hasSecond) {
      newDate.setSeconds(0);
    }
  } else {
    newDate.setHours(0, 0, 0);
  }

  newDate.setMilliseconds(0);
  return newDate;
}

var timeTypes = ['Hours', 'Minutes', 'Seconds'];

function getNearestDate(options, extra, d, calcType) {
  var _options$hasHour = options.hasHour,
      hasHour = _options$hasHour === void 0 ? false : _options$hasHour,
      _options$hasMinute = options.hasMinute,
      hasMinute = _options$hasMinute === void 0 ? false : _options$hasMinute,
      _options$hasSecond = options.hasSecond,
      hasSecond = _options$hasSecond === void 0 ? false : _options$hasSecond;
  var _extra$hourStep = extra.hourStep,
      hourStep = _extra$hourStep === void 0 ? 1 : _extra$hourStep,
      _extra$minuteStep = extra.minuteStep,
      minuteStep = _extra$minuteStep === void 0 ? 1 : _extra$minuteStep,
      _extra$secondStep = extra.secondStep,
      secondStep = _extra$secondStep === void 0 ? 1 : _extra$secondStep;

  var check = function (has, step, timeType) {
    var setter = Date.prototype["set" + timeType];
    var getter = Date.prototype["get" + timeType];

    if (!has) {
      setter.call(d, 0);
    }

    if (step === 1) {
      return;
    }

    var a = getter.call(d);
    var x = a % step;

    if (x > 0) {
      var type = calcType;

      if (type === 'auto') {
        type = x >= step / 2 ? 'plus' : 'minus';
      }

      if (type === 'plus') {
        setter.call(d, a + (step - x));
      } else {
        setter.call(d, a - x);
      }

      for (var i = timeTypes.indexOf(timeType) + 1; i < timeTypes.length; i++) {
        Date.prototype["set" + timeTypes[i]].call(d, 0);
      }
    }
  };

  check(hasSecond, secondStep, 'Seconds');
  check(hasMinute, minuteStep, 'Minutes');
  check(hasHour, hourStep, 'Hours');
  return d;
}

function getRealRange(options, extra, validRange) {
  if (!validRange) {
    return undefined;
  }

  return [getNearestDate(options, extra, cloneDate(validRange[0]), 'plus'), getNearestDate(options, extra, cloneDate(validRange[1]), 'minus')];
}