import create from "../utils/create"; // Components

import Popup from "../popup";
import Button from "../button";
import Toast from "../toast";
import Month from "./components/Month";
import Header from "./components/Header"; // Utils

import { isDate } from "../utils/validate/date";
import Scroll from "../utils/dom/scroll";
import { copyDate, copyDates, getNextDay, compareDay, calcDateNum, compareMonth, getDayByOffset, rangePromptFn } from "./utils";
export default create({
  render: function render() {
    var _attrs;

    var _vm = this;

    var _h = _vm.$createElement;

    var _c = _vm._self._c || _h;

    return _vm.poppable ? _c('Popup', {
      class: _vm.b('popup'),
      attrs: (_attrs = {
        "round": "",
        "value": _vm.value
      }, _attrs["round"] = _vm.round, _attrs["position"] = _vm.position, _attrs["closeable"] = _vm.showTitle || _vm.showSubtitle, _attrs["getContainer"] = _vm.getContainer, _attrs["closeOnPopstate"] = _vm.closeOnPopstate, _attrs["closeOnClickOverlay"] = _vm.closeOnClickOverlay, _attrs),
      on: {
        "input": _vm.togglePopup,
        "open": function open($event) {
          return _vm.onOpen('open');
        },
        "opened": function opened($event) {
          return _vm.onOpen('opened');
        },
        "close": function close($event) {
          return _vm.onOpen('close');
        },
        "closed": function closed($event) {
          return _vm.onOpen('closed');
        }
      }
    }, [_c('div', {
      class: _vm.b()
    }, [_c('Header', {
      attrs: {
        "b": _vm.b,
        "title": _vm.title,
        "showTitle": _vm.showTitle,
        "subtitle": _vm.subtitle,
        "showSubtitle": _vm.showSubtitle,
        "firstDayOfWeek": _vm.dayOffset
      }
    }), _c('div', {
      ref: "body",
      class: _vm.b('body'),
      on: {
        "scroll": _vm.onScroll
      }
    }, _vm._l(_vm.months, function (date, index) {
      return _c('Month', {
        key: index,
        ref: "months",
        refInFor: true,
        attrs: {
          "b": _vm.b,
          "refInFor": "",
          "date": date,
          "type": _vm.type,
          "color": _vm.color,
          "minDate": _vm.minDate,
          "maxDate": _vm.maxDate,
          "showMark": _vm.showMark,
          "formatter": _vm.formatter,
          "rowHeight": _vm.rowHeight,
          "lazyRender": _vm.lazyRender,
          "currentDate": _vm.currentDate,
          "showSubtitle": _vm.showSubtitle,
          "allowSameDay": _vm.allowSameDay,
          "realRowHeight": _vm.realRowHeight,
          "showMonthTitle": index !== 0 || !_vm.showSubtitle,
          "firstDayOfWeek": _vm.dayOffset
        },
        on: {
          "click": _vm.onClickDay,
          "update-height": _vm.onUpdateHeight
        }
      });
    }), 1), _c('div', {
      class: _vm.b('footer', {
        unfit: !_vm.safeAreaInsetBottom
      })
    }, [_vm._t("footer", [_vm.showConfirm ? _c('Button', {
      staticClass: "bg-red",
      class: _vm.b('confirm'),
      attrs: {
        "radius": "mc",
        "block": "",
        "type": "danger",
        "color": _vm.color,
        "background": _vm.background,
        "disabled": _vm.buttonDisabled,
        "nativeType": "button"
      },
      on: {
        "click": _vm.onConfirm
      }
    }, [_vm._v("\n          " + _vm._s(_vm.buttonText || "确定") + "\n        ")]) : _vm._e()])], 2)], 1)]) : _c('div', {
      class: _vm.b()
    }, [_c('Header', {
      attrs: {
        "b": _vm.b,
        "title": _vm.title,
        "showTitle": _vm.showTitle,
        "subtitle": _vm.subtitle,
        "showSubtitle": _vm.showSubtitle,
        "firstDayOfWeek": _vm.dayOffset
      }
    }), _c('div', {
      ref: "body",
      class: _vm.b('body'),
      on: {
        "scroll": _vm.onScroll
      }
    }, _vm._l(_vm.months, function (date, index) {
      return _c('Month', {
        key: index,
        ref: "months",
        refInFor: true,
        attrs: {
          "b": _vm.b,
          "refInFor": "",
          "date": date,
          "type": _vm.type,
          "color": _vm.color,
          "minDate": _vm.minDate,
          "maxDate": _vm.maxDate,
          "showMark": _vm.showMark,
          "formatter": _vm.formatter,
          "rowHeight": _vm.rowHeight,
          "lazyRender": _vm.lazyRender,
          "currentDate": _vm.currentDate,
          "showSubtitle": _vm.showSubtitle,
          "allowSameDay": _vm.allowSameDay,
          "realRowHeight": _vm.realRowHeight,
          "showMonthTitle": index !== 0 || !_vm.showSubtitle,
          "firstDayOfWeek": _vm.dayOffset
        },
        on: {
          "click": _vm.onClickDay,
          "update-height": _vm.onUpdateHeight
        }
      });
    }), 1), _c('div', {
      class: _vm.b('footer', {
        unfit: !_vm.safeAreaInsetBottom
      })
    }, [_vm._t("footer", [_vm.showConfirm ? _c('Button', {
      staticClass: "bg-red",
      class: _vm.b('confirm'),
      attrs: {
        "radius": "mc",
        "block": "",
        "type": "danger",
        "color": _vm.color,
        "background": _vm.background,
        "disabled": _vm.buttonDisabled,
        "nativeType": "button"
      },
      on: {
        "click": _vm.onConfirm
      }
    }, [_vm._v("\n        " + _vm._s(_vm.buttonText || "确定") + "\n      ")]) : _vm._e()])], 2)], 1);
  },
  components: {
    Popup: Popup,
    Button: Button,
    Toast: Toast,
    Month: Month,
    Header: Header
  },
  name: "calendar",
  props: {
    title: String,
    color: String,
    background: String,
    value: Boolean,
    readonly: Boolean,
    formatter: Function,
    rowHeight: [Number, String],
    confirmText: String,
    rangePrompt: String,
    defaultDate: [Date, Array],
    getContainer: [String, Function],
    allowSameDay: Boolean,
    confirmDisabledText: String,
    type: {
      type: String,
      default: "single"
    },
    round: {
      type: Boolean,
      default: true
    },
    position: {
      type: String,
      default: "bottom"
    },
    poppable: {
      type: Boolean,
      default: true
    },
    maxRange: {
      type: [Number, String],
      default: null
    },
    lazyRender: {
      type: Boolean,
      default: true
    },
    showMark: {
      type: Boolean,
      default: true
    },
    showTitle: {
      type: Boolean,
      default: true
    },
    showConfirm: {
      type: Boolean,
      default: true
    },
    showSubtitle: {
      type: Boolean,
      default: true
    },
    closeOnPopstate: {
      type: Boolean,
      default: true
    },
    closeOnClickOverlay: {
      type: Boolean,
      default: true
    },
    safeAreaInsetBottom: {
      type: Boolean,
      default: true
    },
    minDate: {
      type: Date,
      validator: isDate,
      default: function _default() {
        return new Date();
      }
    },
    maxDate: {
      type: Date,
      validator: isDate,
      default: function _default() {
        var now = new Date();
        return new Date(now.getFullYear(), now.getMonth() + 6, now.getDate());
      }
    },
    firstDayOfWeek: {
      type: [Number, String],
      default: 0,
      validator: function validator(val) {
        return val >= 0 && val <= 6;
      }
    }
  },
  watch: {
    type: "reset",
    value: "init",
    defaultDate: function defaultDate(val) {
      this.currentDate = val;
      this.scrollIntoView();
    }
  },
  data: function data() {
    return {
      subtitle: "",
      currentDate: this.getInitialDate(),
      realRowHeight: 0
    };
  },
  mounted: function mounted() {
    this.init();
  },

  /* istanbul ignore next */
  activated: function activated() {
    this.init();
  },
  methods: {
    // @exposed-api
    reset: function reset() {
      this.currentDate = this.getInitialDate();
      this.scrollIntoView();
    },
    init: function init() {
      var _this = this;

      if (this.poppable && !this.value) {
        return;
      }

      this.$nextTick(function () {
        // add Math.floor to avoid decimal height issues
        // https://github.com/youzan/vant/issues/5640
        _this.bodyHeight = Math.floor(_this.$refs.body.getBoundingClientRect().height);

        _this.onScroll();
      });
      this.scrollIntoView();
    },
    // scroll to current month
    scrollIntoView: function scrollIntoView() {
      var _this2 = this;

      this.$nextTick(function () {
        var currentDate = _this2.currentDate;

        if (!currentDate) {
          return;
        }

        var targetDate = _this2.type === "single" ? currentDate : currentDate[0];
        var displayed = _this2.value || !_this2.poppable;
        /* istanbul ignore if */

        if (!targetDate || !displayed) {
          return;
        }

        _this2.months.some(function (month, index) {
          if (compareMonth(month, targetDate) === 0) {
            var _this2$$refs = _this2.$refs,
                body = _this2$$refs.body,
                months = _this2$$refs.months;
            months[index].scrollIntoView(body);
            return true;
          }

          return false;
        });
      });
    },
    getInitialDate: function getInitialDate() {
      var type = this.type,
          minDate = this.minDate,
          maxDate = this.maxDate,
          defaultDate = this.defaultDate;

      if (defaultDate === null) {
        return defaultDate;
      }

      var defaultVal = new Date();

      if (compareDay(defaultVal, minDate) === -1) {
        defaultVal = minDate;
      } else if (compareDay(defaultVal, maxDate) === 1) {
        defaultVal = maxDate;
      }

      if (type === "range") {
        var _ref = defaultDate || [],
            startDay = _ref[0],
            endDay = _ref[1];

        return [startDay || defaultVal, endDay || getNextDay(defaultVal)];
      }

      if (type === "multiple") {
        return defaultDate || [defaultVal];
      }

      return defaultDate || defaultVal;
    },
    // calculate the position of the elements
    // and find the elements that needs to be rendered
    onScroll: function onScroll() {
      var _this$$refs = this.$refs,
          body = _this$$refs.body,
          months = _this$$refs.months;
      var top = Scroll.getScrollTop(body);
      var heights = months.map(function (item) {
        return item.getHeight();
      });
      var heightSum = heights.reduce(function (a, b) {
        return a + b;
      }, 0); // iOS scroll bounce may exceed the range

      var bottom = top + this.bodyHeight;

      if (bottom > heightSum && top > 0) {
        bottom = heightSum;
      }

      var height = 0;
      var currentMonth; // add offset to avoid rem accuracy issues
      // see: https://github.com/youzan/vant/issues/6929

      var viewportOffset = 50;
      var viewportTop = top - viewportOffset;
      var viewportBottom = bottom + viewportOffset;

      for (var i = 0; i < months.length; i++) {
        var visible = height <= viewportBottom && height + heights[i] >= viewportTop;

        if (visible && !currentMonth) {
          currentMonth = months[i];
        }

        if (!months[i].visible && visible) {
          this.$emit("month-show", {
            date: months[i].date,
            title: months[i].title
          });
        }

        months[i].visible = visible;
        height += heights[i];
      }
      /* istanbul ignore else */


      if (currentMonth) {
        this.subtitle = currentMonth.title;
      }
    },
    onClickDay: function onClickDay(item) {
      if (this.readonly) {
        return;
      }

      var date = item.date;
      var type = this.type,
          currentDate = this.currentDate;

      if (type === "range") {
        if (!currentDate) {
          this.select([date, null]);
          return;
        }

        var startDay = currentDate[0],
            endDay = currentDate[1];

        if (startDay && !endDay) {
          var compareToStart = compareDay(date, startDay);

          if (compareToStart === 1) {
            this.select([startDay, date], true);
          } else if (compareToStart === -1) {
            this.select([date, null]);
          } else if (this.allowSameDay) {
            this.select([date, date], true);
          }
        } else {
          this.select([date, null]);
        }
      } else if (type === "multiple") {
        if (!currentDate) {
          this.select([date]);
          return;
        }

        var selectedIndex;
        var selected = this.currentDate.some(function (dateItem, index) {
          var equal = compareDay(dateItem, date) === 0;

          if (equal) {
            selectedIndex = index;
          }

          return equal;
        });

        if (selected) {
          var _currentDate$splice = currentDate.splice(selectedIndex, 1),
              unselectedDate = _currentDate$splice[0];

          this.$emit("unselect", copyDate(unselectedDate));
        } else if (this.maxRange && currentDate.length >= this.maxRange) {
          Toast(this.rangePrompt || rangePromptFn(this.maxRange));
        } else {
          this.select([].concat(currentDate, [date]));
        }
      } else {
        this.select(date, true);
      }
    },
    togglePopup: function togglePopup(val) {
      this.$emit("input", val);
    },
    onOpen: function onOpen(name) {
      this.$emit(name);
    },
    select: function select(date, complete) {
      var _this3 = this;

      var emit = function emit(date) {
        _this3.currentDate = date;

        _this3.$emit("select", copyDates(_this3.currentDate));
      };

      if (complete && this.type === "range") {
        var valid = this.checkRange(date);

        if (!valid) {
          // auto selected to max range if showConfirm
          if (this.showConfirm) {
            emit([date[0], getDayByOffset(date[0], this.maxRange - 1)]);
          } else {
            emit(date);
          }

          return;
        }
      }

      emit(date);

      if (complete && !this.showConfirm) {
        this.onConfirm();
      }
    },
    checkRange: function checkRange(date) {
      var maxRange = this.maxRange,
          rangePrompt = this.rangePrompt;

      if (maxRange && calcDateNum(date) > maxRange) {
        Toast(rangePrompt || rangePromptFn(maxRange));
        return false;
      }

      return true;
    },
    onConfirm: function onConfirm() {
      this.$emit("confirm", copyDates(this.currentDate));
    },
    onUpdateHeight: function onUpdateHeight(height) {
      this.realRowHeight = height;
    }
  },
  computed: {
    buttonText: function buttonText() {
      return this.buttonDisabled ? this.confirmDisabledText : this.confirmText;
    },
    months: function months() {
      var months = [];
      var cursor = new Date(this.minDate);
      cursor.setDate(1);

      do {
        months.push(new Date(cursor));
        cursor.setMonth(cursor.getMonth() + 1);
      } while (compareMonth(cursor, this.maxDate) !== 1);

      return months;
    },
    buttonDisabled: function buttonDisabled() {
      var type = this.type,
          currentDate = this.currentDate;

      if (currentDate) {
        if (type === "range") {
          return !currentDate[0] || !currentDate[1];
        }

        if (type === "multiple") {
          return !currentDate.length;
        }
      }

      return !currentDate;
    },
    dayOffset: function dayOffset() {
      return this.firstDayOfWeek ? this.firstDayOfWeek % 7 : 0;
    }
  }
});