import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
import { reactive, watch, ref, computed } from 'vue';
import { isNil } from 'lodash-es';
import { endOfMonth } from 'date-fns';
import getPrefixCls from '../_util/getPrefixCls';
import { useNormalModel } from '../_util/use/useModel';
import { useLocale } from '../config-provider/useLocale';
import { PickerType } from './pickerHandler';
import { YEAR_COUNT, SELECTED_STATUS, RANGE_POSITION } from './const';
import { parseDate, transformDateToTimestamp, fillDate, contrastDate, timeFormat, transformTimeToDate } from './helper';

function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
const prefixCls = getPrefixCls('date-picker-calendar');
const WEEK_NAMES = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
const useCurrentDate = (props, emit) => {
  const currentDate = reactive(parseDate(props.activeDate));
  const [innerActiveDate, updateActiveDate] = useNormalModel(props, emit, {
    prop: 'activeDate'
  });
  const mergeCurrentDate = date => {
    Object.assign(currentDate, date);
    currentDate.day = 1;
  };
  const updateCurrentDate = date => {
    mergeCurrentDate(date);
    updateActiveDate(transformDateToTimestamp(currentDate));
  };
  watch(innerActiveDate, () => {
    mergeCurrentDate(parseDate(innerActiveDate.value));
  });
  watch(() => props.modelValue, () => {
    var _props$modelValue;
    if (((_props$modelValue = props.modelValue) === null || _props$modelValue === void 0 ? void 0 : _props$modelValue.length) === 1 && !props.rangePosition) {
      updateCurrentDate(parseDate(props.modelValue[0]));
    }
  });
  return {
    currentDate,
    updateCurrentDate
  };
};
const useSelectedDates = (props, emit, picker) => {
  const selectedDates = ref([]);
  const updateRangeSelectedDates = (date, index) => {
    if (!selectedDates.value.length || index === 0 && transformDateToTimestamp(date) > transformDateToTimestamp(selectedDates.value[1]) || index === 1 && transformDateToTimestamp(date) < transformDateToTimestamp(selectedDates.value[0])) {
      selectedDates.value = [date, _objectSpread({}, date)];
    } else {
      selectedDates.value.splice(index, 1, date);
    }
  };
  const updateSelectedDates = function (date, index) {
    let option = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
    const newDate = Object.assign({}, selectedDates.value[index], date);
    if (picker.value.isRange && option.isTime) {
      updateRangeSelectedDates(newDate, index);
    } else if (picker.value.isRange && option.isDateInput && props.selectedStatus === SELECTED_STATUS.END) {
      updateRangeSelectedDates(newDate, index);
    } else if (picker.value.isRange && (!selectedDates.value.length || props.selectedStatus === SELECTED_STATUS.END)) {
      const anotherDate = fillDate({
        dateObj: newDate,
        format: picker.value.format,
        defaultTime: props.defaultTime,
        rangePosition: props.rangePosition === RANGE_POSITION.LEFT ? RANGE_POSITION.RIGHT : RANGE_POSITION.LEFT
      });
      if (props.rangePosition === RANGE_POSITION.LEFT) {
        selectedDates.value = [newDate, anotherDate];
      } else {
        selectedDates.value = [anotherDate, newDate];
      }
      emit('selectedDay');
    } else if (picker.value.name === PickerType.datemultiple) {
      const selectedDateIndex = selectedDates.value.findIndex(item => {
        return item.year === newDate.year && item.month === newDate.month && item.day === newDate.day;
      });
      if (selectedDateIndex !== -1) {
        selectedDates.value.splice(selectedDateIndex, 1);
      } else {
        selectedDates.value.push(newDate);
      }
    } else if (!picker.value.isRange) {
      selectedDates.value = [newDate];
    } else {
      if (
      // 变更日期的时候，继承当前位置的时间
      transformDateToTimestamp(selectedDates.value[0]) > transformDateToTimestamp(newDate)) {
        selectedDates.value.splice(0, 1, picker.value.getRangeSelectedDate(newDate, selectedDates.value[0]));
      } else {
        selectedDates.value.splice(1, 1, picker.value.getRangeSelectedDate(newDate, selectedDates.value[1]));
      }
      emit('selectedDay');
    }
    if (picker.value.isRange) {
      emit('change', [transformDateToTimestamp(selectedDates.value[0]), transformDateToTimestamp(selectedDates.value[1], true)]);
    } else if (picker.value.name === PickerType.datemultiple) {
      emit('change', selectedDates.value.map(item => {
        return transformDateToTimestamp(item);
      }));
    } else {
      emit('change', [transformDateToTimestamp(selectedDates.value[0])]);
    }
  };
  watch(() => props.modelValue, () => {
    const dates = props.modelValue || [];
    selectedDates.value = dates.map(item => item ? parseDate(item) : null);
  }, {
    immediate: true
  });
  return {
    selectedDates,
    updateSelectedDates
  };
};
function useYear(_ref) {
  let {
    props,
    selectedDates,
    updateSelectedDates,
    activeIndex,
    currentDate,
    updateCurrentDate
  } = _ref;
  const isYearSelect = computed(() => props.type === PickerType.year);
  // 年份相关
  const selectYear = year => {
    updateCurrentDate({
      year
    });
    updateSelectedDates({
      year
    }, activeIndex.value);
  };
  const yearStart = computed(() => currentDate.year - currentDate.year % YEAR_COUNT);
  const yearEnd = computed(() => yearStart.value + YEAR_COUNT);
  const years = computed(() => {
    const arr = [];
    let start = yearStart.value;
    while (arr.length < 16) {
      arr.push(start++);
    }
    return arr;
  });
  const disabled = year => {
    const date = new Date(year, 0);
    return props.disabledDate && props.disabledDate(date, 'yyyy');
  };
  const isSelectedYear = year => {
    if (props.type === PickerType.year) {
      return !!selectedDates.value.find(item => (item === null || item === void 0 ? void 0 : item.year) === year);
    }
    return false;
  };
  const yearCls = year => [`${prefixCls}-date`, disabled(year) && `${prefixCls}-date-disabled`, isSelectedYear(year) && `${prefixCls}-date-selected`, year === new Date().getFullYear() && [`${prefixCls}-date-now`]];
  return {
    years,
    yearStart,
    yearEnd,
    selectYear,
    isYearSelect,
    yearCls
  };
}
function useCommonRange(_ref2) {
  let {
    props,
    selectedDates,
    picker
  } = _ref2;
  const startDate = computed(() => selectedDates.value[0] && new Date(transformDateToTimestamp(selectedDates.value[0])));
  const endDate = computed(() => selectedDates.value[1] && new Date(transformDateToTimestamp(selectedDates.value[1])));

  // 样式计算
  const inRangeDate = (date, format) => {
    if (picker.value.isRange && startDate.value && endDate.value) {
      return contrastDate(date, startDate.value, format) === 1 && contrastDate(date, endDate.value, format) === -1;
    }
    return false;
  };
  const completeRangeSelected = computed(() => props.selectedStatus === SELECTED_STATUS.END);
  return {
    completeRangeSelected,
    inRangeDate
  };
}
function useMonth(_ref3) {
  let {
    props,
    selectedDates,
    updateSelectedDates,
    activeIndex,
    currentDate,
    updateCurrentDate,
    picker
  } = _ref3;
  // 月份相关
  const format = 'yyyy-MM';
  const isMonthSelect = computed(() => {
    return props.type === PickerType.month || props.type === PickerType.datemonthrange;
  });
  const selectMonth = month => {
    updateSelectedDates({
      year: currentDate.year,
      month,
      day: props.type === PickerType.month || props.rangePosition === RANGE_POSITION.LEFT ? 1 : endOfMonth(new Date(currentDate.year, month, 1)).getDate()
    }, activeIndex.value);
  };
  const monthToNext = () => {
    if (currentDate.month < 11) {
      updateCurrentDate({
        year: currentDate.year,
        month: currentDate.month + 1
      });
    } else {
      updateCurrentDate({
        year: currentDate.year + 1,
        month: 0
      });
    }
  };
  const monthToPre = () => {
    if (currentDate.month > 0) {
      updateCurrentDate({
        year: currentDate.year,
        month: currentDate.month - 1
      });
    } else {
      updateCurrentDate({
        month: 11,
        year: currentDate.year - 1
      });
    }
  };
  const disabled = month => {
    const date = new Date(currentDate.year, month);
    return props.disabledDate && props.disabledDate(date, format);
  };
  const isSelectedMonth = month => {
    if (isMonthSelect.value) {
      return selectedDates.value.findIndex(item => item && item.year === currentDate.year && item.month === month);
    }
    return -1;
  };
  const {
    completeRangeSelected,
    inRangeDate
  } = useCommonRange({
    props,
    selectedDates,
    picker
  });
  const monthCls = month => {
    const selectedIndex = isSelectedMonth(month);
    const date = new Date(currentDate.year, month);
    return {
      [`${prefixCls}-date`]: true,
      [`${prefixCls}-date-disabled`]: disabled(month),
      [`${prefixCls}-date-selected`]: selectedIndex !== -1,
      'is-start': picker.value.isRange && completeRangeSelected.value && selectedIndex === 0,
      'is-end': picker.value.isRange && completeRangeSelected.value && selectedIndex === 1,
      [`${prefixCls}-date-now`]: timeFormat(new Date(currentDate.year, month), format) === timeFormat(new Date(), format),
      [`${prefixCls}-date-on`]: inRangeDate(date, format)
    };
  };
  return {
    isMonthSelect,
    selectMonth,
    monthToNext,
    monthToPre,
    monthCls
  };
}
function useDay(_ref4) {
  let {
    props,
    selectedDates,
    currentDate,
    picker
  } = _ref4;
  const {
    t
  } = useLocale();

  // TODO 英文一个星期的第一天是 周日
  const weekFirstDay = ref(1);
  // 展示数据
  const weekNames = computed(() => {
    const weekFirstDayValue = weekFirstDay.value;
    return WEEK_NAMES.concat(WEEK_NAMES).slice(weekFirstDayValue, weekFirstDayValue + 7).map(_ => t(`datePicker.weeks.${_}`));
  });
  const isDaySelect = computed(() => [PickerType.date, PickerType.datetime, PickerType.daterange, PickerType.datetimerange, PickerType.datemultiple].some(type => props.type === type));
  const days = computed(() => {
    const daysTemp = [];
    const {
      year,
      month
    } = currentDate;
    const time = new Date(year, month, 1);
    const weekFirstDayValue = weekFirstDay.value;
    time.setDate(0); // switch to the last day of last month
    let lastDay = time.getDate();
    const week = time.getDay() || 7;
    let count = weekFirstDayValue <= week ? week - weekFirstDayValue + 1 : week + (7 - weekFirstDayValue + 1);
    while (count > 0 && count < 7) {
      daysTemp.push({
        day: lastDay - count + 1,
        year: month > 0 ? year : year - 1,
        month: month > 0 ? month - 1 : 11,
        pre: true
      });
      count--;
    }
    time.setMonth(time.getMonth() + 2, 0); // switch to the last day of the current month
    lastDay = time.getDate();
    let i = 1;
    for (i = 1; i <= lastDay; i++) {
      daysTemp.push({
        day: i,
        year,
        month
      });
    }
    for (i = 1; daysTemp.length < 42; i++) {
      daysTemp.push({
        day: i,
        year: month < 11 ? year : year + 1,
        month: month < 11 ? month + 1 : 0,
        next: true
      });
    }
    return daysTemp;
  });
  const isSelected = (selectedDate, dayItem) => dayItem.year === (selectedDate === null || selectedDate === void 0 ? void 0 : selectedDate.year) && dayItem.month === (selectedDate === null || selectedDate === void 0 ? void 0 : selectedDate.month) && dayItem.month === currentDate.month && dayItem.day === (selectedDate === null || selectedDate === void 0 ? void 0 : selectedDate.day);
  const findSelectedIndex = dayItem => selectedDates.value.findIndex(selectedDate => isSelected(selectedDate, dayItem));
  const computedSelectedStart = dayItem => {
    return picker.value.isRange && completeRangeSelected.value && isSelected(selectedDates.value[0], dayItem);
  };
  const computedSelectedEnd = dayItem => {
    return picker.value.isRange && completeRangeSelected.value && isSelected(selectedDates.value[1], dayItem);
  };
  const {
    completeRangeSelected,
    inRangeDate
  } = useCommonRange({
    props,
    selectedDates,
    picker
  });
  const dayCls = item => {
    const format = 'yyyy-MM-dd';
    const {
      year,
      month
    } = item;
    const date = new Date(year, month, item.day);
    const selectedIndex = findSelectedIndex(item);
    return {
      [`${prefixCls}-date-out`]: item.pre || item.next,
      [`${prefixCls}-date`]: true,
      [`${prefixCls}-date-disabled`]: props.disabledDate && props.disabledDate(date, format),
      [`${prefixCls}-date-selected`]: selectedIndex !== -1,
      'is-start': computedSelectedStart(item),
      'is-end': computedSelectedEnd(item),
      [`${prefixCls}-date-now`]: timeFormat(date, format) === timeFormat(new Date(), format),
      [`${prefixCls}-date-on`]: inRangeDate(date, format) && date.getMonth() === currentDate.month
    };
  };
  return {
    days,
    isDaySelect,
    weekNames,
    dayCls
  };
}
const useQuarter = (props, selectedDates, updateSelectedDates, activeIndex, currentDate) => {
  const isQuarterSelect = computed(() => props.type === PickerType.quarter);
  const format = 'yyyy-MM';
  const quarterList = [{
    name: 'Q1',
    value: 1
  }, {
    name: 'Q2',
    value: 2
  }, {
    name: 'Q3',
    value: 3
  }, {
    name: 'Q4',
    value: 4
  }];
  const selectQuarter = item => {
    updateSelectedDates({
      year: currentDate.year,
      month: (item.value - 1) * 3
    }, activeIndex.value);
  };
  const isSelected = item => !!selectedDates.value.find(selectedDate => selectedDate && selectedDate.year === currentDate.year && item.value === Math.floor(selectedDate.month / 3) + 1);
  const isNow = item => {
    const now = parseDate();
    return now.year === currentDate.year && Math.floor(now.month / 3) + 1 === item.value;
  };

  // 季度置灰判断
  const isDisabled = item => {
    const year = currentDate.year;
    const month = (item.value - 1) * 3;
    const date = new Date(year, month);
    return props.disabledDate && props.disabledDate(date, format);
  };
  const quarterCls = item => ({
    [`${prefixCls}-date`]: true,
    [`${prefixCls}-date-selected`]: isSelected(item),
    [`${prefixCls}-date-now`]: isNow(item),
    [`${prefixCls}-date-disabled`]: isDisabled(item)
  });
  return {
    isQuarterSelect,
    quarterList,
    selectQuarter,
    quarterCls
  };
};
const transformDateToTime = selectedDate => {
  if (!selectedDate) {
    return '';
  }
  const times = [];
  if (!isNil(selectedDate.hour)) {
    times.push(`${selectedDate.hour}`.padStart(2, '0'));
  }
  if (!isNil(selectedDate.minute)) {
    times.push(`${selectedDate.minute}`.padStart(2, '0'));
  }
  if (!isNil(selectedDate.second)) {
    times.push(`${selectedDate.second}`.padStart(2, '0'));
  }
  return times.join(':');
};
const useTime = _ref5 => {
  let {
    props,
    selectedDates,
    updateSelectedDates,
    activeIndex,
    picker
  } = _ref5;
  const currentTime = ref('');
  watch([selectedDates], () => {
    currentTime.value = transformDateToTime(selectedDates.value[activeIndex.value]);
  }, {
    immediate: true,
    deep: true
  });
  const changeTime = time => {
    if (time) {
      var _selectedDates$value$;
      const selectedDate = _objectSpread(_objectSpread({}, selectedDates.value[activeIndex.value]), transformTimeToDate(time));
      if (!((_selectedDates$value$ = selectedDates.value[activeIndex.value]) !== null && _selectedDates$value$ !== void 0 && _selectedDates$value$.year)) {
        const date = new Date();
        Object.assign(selectedDate, {
          year: date.getFullYear(),
          month: date.getMonth(),
          day: date.getDate()
        });
      }
      updateSelectedDates(selectedDate, activeIndex.value, {
        isTime: true
      });
    }
  };
  const innerDisabledTime = computed(() => {
    if (!props.disabledTime) {
      return null;
    }
    if (picker.value.isRange) {
      return props.disabledTime(new Date(transformDateToTimestamp(selectedDates.value[activeIndex.value])), props.rangePosition, selectedDates.value.map(val => {
        return new Date(transformDateToTimestamp(val));
      }));
    }
    return props.disabledTime(new Date(transformDateToTimestamp(selectedDates.value[0])));
  });
  return {
    currentTime,
    changeTime,
    innerDisabledTime
  };
};

export { useCommonRange, useCurrentDate, useDay, useMonth, useQuarter, useSelectedDates, useTime, useYear };
