import { h, Host } from '@stencil/core';
import classNames from 'classnames';
import { hoursRange, minutesRange, compareTime, verifyValue, verifyTime, verifyDate, getYearRange, getMonthRange, getDayRange, formatValue } from './utils';
import { TOP, LINE_HEIGHT } from './constant';
export class Picker {
  constructor() {
    this.index = [];
    // 展示 Picker
    this.showPicker = () => {
      if (this.disabled)
        return;
      this.height = this.getHeightByIndex();
      this.hidden = false;
    };
    this.getHeightByIndex = () => {
      const height = this.index.map(i => {
        let factor = 0;
        if (this.mode === 'time') {
          factor = LINE_HEIGHT * 4;
        }
        return TOP - LINE_HEIGHT * i - factor;
      });
      return height;
    };
    // 隐藏 picker
    this.hidePicker = () => {
      this.fadeOut = true;
      setTimeout(() => {
        this.hidden = true;
        this.fadeOut = false;
      }, 350);
    };
    // 点击确定按钮
    this.handleChange = () => {
      this.hidePicker();
      this.index = this.height.map(h => (TOP - h) / LINE_HEIGHT);
      let value = this.index.length && this.mode !== 'selector'
        ? this.index
        : this.index[0];
      if (this.mode === 'time') {
        const range = [hoursRange.slice(), minutesRange.slice()];
        const timeArr = this.index.map((n, i) => range[i][n]);
        this.index = timeArr.map(item => parseInt(item));
        value = timeArr.join(':');
      }
      if (this.mode === 'date') {
        const { _start, _end, _updateValue } = this.pickerDate;
        const currentYear = _updateValue[0];
        const currentMonth = _updateValue[1];
        const yearRange = getYearRange(_start.getFullYear(), _end.getFullYear());
        const monthRange = getMonthRange(_start, _end, currentYear);
        const dayRange = getDayRange(_start, _end, currentYear, currentMonth);
        const year = yearRange[this.index[0]];
        const month = monthRange[this.index[1]];
        const day = dayRange[this.index[2]];
        if (this.fields === 'year') {
          value = [year];
        }
        else if (this.fields === 'month') {
          value = [year, month];
        }
        else {
          value = [year, month, day];
        }
        value = value
          .map(item => {
          return item < 10 ? `0${item}` : item;
        })
          .join('-');
      }
      this.pickerValue = value;
      this.onChange.emit({
        value
      });
    };
    // 点击取消按钮或蒙层
    this.handleCancel = () => {
      this.hidePicker();
      this.onCancel.emit();
    };
    this.updateHeight = (height, columnId, needRevise = false) => {
      const temp = [...this.height];
      temp[columnId] = height;
      this.height = temp;
      // time picker 必须在规定时间范围内，因此需要在 touchEnd 做修正
      if (needRevise) {
        let { start, end } = this;
        if (!verifyTime(start))
          start = '00:00';
        if (!verifyTime(end))
          end = '23:59';
        if (!compareTime(start, end))
          return;
        const range = [hoursRange.slice(), minutesRange.slice()];
        const timeList = this.height.map(h => (TOP - h) / LINE_HEIGHT);
        const timeStr = timeList.map((n, i) => range[i][n]).join(':');
        if (!compareTime(start, timeStr)) {
          // 修正到 start
          const height = start
            .split(':')
            .map(i => TOP - LINE_HEIGHT * (+i + 4));
          requestAnimationFrame(() => (this.height = height));
        }
        else if (!compareTime(timeStr, end)) {
          // 修正到 end
          const height = end
            .split(':')
            .map(i => TOP - LINE_HEIGHT * (+i + 4));
          requestAnimationFrame(() => (this.height = height));
        }
      }
    };
    this.handleColumnChange = (height, columnId) => {
      this.onColumnChange.emit({
        column: Number(columnId),
        value: (TOP - height) / LINE_HEIGHT
      });
    };
    this.updateDay = (value, fields) => {
      const { _start, _end, _updateValue } = this.pickerDate;
      _updateValue[fields] = value;
      const currentYear = _updateValue[0];
      const currentMonth = _updateValue[1];
      const currentDay = _updateValue[2];
      // 滚动年份
      if (fields === 0) {
        const monthRange = getMonthRange(_start, _end, currentYear);
        const max = monthRange[monthRange.length - 1];
        const min = monthRange[0];
        if (currentMonth > max)
          _updateValue[1] = max;
        if (currentMonth < min)
          _updateValue[1] = min;
        const index = monthRange.indexOf(_updateValue[1]);
        const height = TOP - LINE_HEIGHT * index;
        this.updateDay(_updateValue[1], 1);
        this.updateHeight(height, '1');
      }
      else if (fields === 1) {
        const dayRange = getDayRange(_start, _end, currentYear, currentMonth);
        const max = dayRange[dayRange.length - 1];
        const min = dayRange[0];
        if (currentDay > max)
          _updateValue[2] = max;
        if (currentDay < min)
          _updateValue[2] = min;
        const index = dayRange.indexOf(_updateValue[2]);
        const height = TOP - LINE_HEIGHT * index;
        this.updateDay(_updateValue[2], 2);
        this.updateHeight(height, '2');
      }
    };
    // 单列选择器
    this.getSelector = () => {
      return (h("taro-picker-group", { range: this.range, rangeKey: this.rangeKey, height: this.height[0], updateHeight: this.updateHeight, columnId: '0' }));
    };
    // 多列选择器
    this.getMultiSelector = () => {
      return this.range.map((range, index) => {
        return (h("taro-picker-group", { range: range, rangeKey: this.rangeKey, height: this.height[index], updateHeight: this.updateHeight, onColumnChange: this.handleColumnChange, columnId: String(index) }));
      });
    };
    // 时间选择器
    this.getTimeSelector = () => {
      const hourRange = hoursRange.slice();
      const minRange = minutesRange.slice();
      return [
        h("taro-picker-group", { mode: 'time', range: hourRange, height: this.height[0], updateHeight: this.updateHeight, columnId: '0' }),
        h("taro-picker-group", { mode: 'time', range: minRange, height: this.height[1], updateHeight: this.updateHeight, columnId: '1' })
      ];
    };
    // 日期选择器
    this.getDateSelector = () => {
      const { fields, height } = this;
      const { _start, _end, _updateValue } = this.pickerDate;
      const currentYear = _updateValue[0];
      const currentMonth = _updateValue[1];
      const yearRange = getYearRange(_start.getFullYear(), _end.getFullYear())
        .map(item => `${item}年`);
      const monthRange = getMonthRange(_start, _end, currentYear)
        .map(item => `${item < 10 ? `0${item}` : item}月`);
      const dayRange = getDayRange(_start, _end, currentYear, currentMonth)
        .map(item => `${item < 10 ? `0${item}` : item}日`);
      const renderView = [
        h("taro-picker-group", { mode: 'date', range: yearRange, height: height[0], updateDay: this.updateDay, updateHeight: this.updateHeight, columnId: '0' })
      ];
      if (fields === 'month' || fields === 'day') {
        renderView.push(h("taro-picker-group", { mode: 'date', range: monthRange, height: height[1], updateDay: this.updateDay, updateHeight: this.updateHeight, columnId: '1' }));
      }
      if (fields === 'day') {
        renderView.push(h("taro-picker-group", { mode: 'date', range: dayRange, height: height[2], updateDay: this.updateDay, updateHeight: this.updateHeight, columnId: '2' }));
      }
      return renderView;
    };
    this.mode = 'selector';
    this.disabled = false;
    this.range = [];
    this.rangeKey = undefined;
    this.value = undefined;
    this.start = '';
    this.end = '';
    this.fields = 'day';
    this.name = '';
    this.pickerValue = [];
    this.height = [];
    this.hidden = true;
    this.fadeOut = false;
    this.isWillLoadCalled = false;
  }
  componentWillLoad() {
    this.isWillLoadCalled = true;
    this.handleProps();
  }
  componentDidLoad() {
    Object.defineProperty(this.el, 'value', {
      get: () => this.pickerValue,
      set: val => (this.value = val),
      configurable: true
    });
    if (this.overlay) {
      document.body.appendChild(this.overlay);
    }
  }
  disconnectedCallback() {
    var _a;
    if (this.overlay) {
      (_a = this.overlay.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(this.overlay);
    }
  }
  onPropsChange() {
    if (!this.isWillLoadCalled)
      return;
    this.handleProps();
  }
  handleProps() {
    const { mode, start, end } = this;
    if (mode === 'selector') {
      const value = this.value;
      this.index = [verifyValue(value, this.range) ? Math.floor(value) : 0];
    }
    else if (mode === 'multiSelector') {
      const value = this.value;
      this.index = [];
      this.range.forEach((range, index) => {
        const val = value === null || value === void 0 ? void 0 : value[index];
        const item = verifyValue(val, range) ? Math.floor(val) : 0;
        this.index.push(item);
      });
    }
    else if (mode === 'time') {
      let value = this.value;
      // check value...
      if (!verifyTime(value)) {
        console.warn('time picker value illegal');
        value = '0:0';
      }
      const time = value.split(':').map(n => +n);
      this.index = time;
    }
    else if (mode === 'date') {
      const value = this.value;
      const _value = verifyDate(value) || new Date(new Date().setHours(0, 0, 0, 0)); // 没传值或值的合法性错误默认今天时间
      const _start = verifyDate(start) || new Date('1970/01/01');
      const _end = verifyDate(end) || new Date('2999/01/01');
      // 时间区间有效性
      if (_value >= _start && _value <= _end) {
        const currentYear = _value.getFullYear();
        const currentMonth = _value.getMonth() + 1;
        const currentDay = _value.getDate();
        const yearRange = getYearRange(_start.getFullYear(), _end.getFullYear());
        const monthRange = getMonthRange(_start, _end, currentYear);
        const dayRange = getDayRange(_start, _end, currentYear, currentMonth);
        this.index = [
          yearRange.indexOf(currentYear),
          monthRange.indexOf(currentMonth),
          dayRange.indexOf(currentDay)
        ];
        if (!this.pickerDate ||
          this.pickerDate._value.getTime() !== _value.getTime() ||
          this.pickerDate._start.getTime() !== _start.getTime() ||
          this.pickerDate._end.getTime() !== _end.getTime()) {
          this.pickerDate = {
            _value,
            _start,
            _end,
            _updateValue: [
              currentYear,
              currentMonth,
              currentDay
            ]
          };
        }
      }
      else {
        throw new Error('Date Interval Error');
      }
    }
    // Prop 变化时，无论是否正在显示弹层，都更新 height 值
    this.height = this.getHeightByIndex();
    // 同步表单 value 值，用于 form submit
    this.pickerValue = this.value;
    if (mode === 'date') {
      const val = this.pickerValue;
      if (this.fields === 'month') {
        this.pickerValue = val.split('-').slice(0, 2).join('-');
      }
      else if (this.fields === 'year') {
        this.pickerValue = val.split('-')[0];
      }
    }
  }
  render() {
    const { name, mode, fadeOut, hidden } = this;
    // 选项条
    let pickerGroup;
    switch (mode) {
      case 'multiSelector':
        pickerGroup = this.getMultiSelector();
        break;
      case 'time':
        pickerGroup = this.getTimeSelector();
        break;
      case 'date':
        pickerGroup = this.getDateSelector();
        break;
      default:
        pickerGroup = this.getSelector();
    }
    // 动画类名控制逻辑
    const clsMask = classNames('weui-mask', 'weui-animate-fade-in', {
      'weui-animate-fade-out': fadeOut
    });
    const clsSlider = classNames('weui-picker', 'weui-animate-slide-up', {
      'weui-animate-slide-down': fadeOut
    });
    const shouldDivHidden = hidden ? { display: 'none' } : {};
    return (h(Host, null, h("div", { onClick: this.showPicker }, h("slot", null), h("input", { type: 'hidden', name: name, value: formatValue(this.pickerValue) })), h("div", { class: 'weui-picker__overlay', style: shouldDivHidden, ref: el => { this.overlay = el; } }, h("div", { class: clsMask, onClick: this.handleCancel }), h("div", { class: clsSlider }, h("div", { class: 'weui-picker__hd' }, h("div", { class: 'weui-picker__action', onClick: this.handleCancel }, "\u53D6\u6D88"), h("div", { class: 'weui-picker__action', onClick: this.handleChange }, "\u786E\u5B9A")), h("div", { class: 'weui-picker__bd' }, pickerGroup), h("input", { type: 'hidden', name: name, value: formatValue(this.pickerValue) })))));
  }
  static get is() { return "taro-picker-core"; }
  static get originalStyleUrls() {
    return {
      "$": ["./style/index.scss"]
    };
  }
  static get styleUrls() {
    return {
      "$": ["./style/index.css"]
    };
  }
  static get properties() {
    return {
      "mode": {
        "type": "string",
        "mutable": false,
        "complexType": {
          "original": "Mode",
          "resolved": "\"date\" | \"multiSelector\" | \"selector\" | \"time\"",
          "references": {
            "Mode": {
              "location": "local"
            }
          }
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": ""
        },
        "attribute": "mode",
        "reflect": false,
        "defaultValue": "'selector'"
      },
      "disabled": {
        "type": "boolean",
        "mutable": false,
        "complexType": {
          "original": "boolean",
          "resolved": "boolean",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": ""
        },
        "attribute": "disabled",
        "reflect": false,
        "defaultValue": "false"
      },
      "range": {
        "type": "unknown",
        "mutable": false,
        "complexType": {
          "original": "any[]",
          "resolved": "any[]",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": ""
        },
        "defaultValue": "[]"
      },
      "rangeKey": {
        "type": "string",
        "mutable": false,
        "complexType": {
          "original": "string",
          "resolved": "string",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": ""
        },
        "attribute": "range-key",
        "reflect": false
      },
      "value": {
        "type": "any",
        "mutable": true,
        "complexType": {
          "original": "number | number[] | string",
          "resolved": "number | number[] | string",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": ""
        },
        "attribute": "value",
        "reflect": false
      },
      "start": {
        "type": "string",
        "mutable": false,
        "complexType": {
          "original": "string",
          "resolved": "string",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": ""
        },
        "attribute": "start",
        "reflect": false,
        "defaultValue": "''"
      },
      "end": {
        "type": "string",
        "mutable": false,
        "complexType": {
          "original": "string",
          "resolved": "string",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": ""
        },
        "attribute": "end",
        "reflect": false,
        "defaultValue": "''"
      },
      "fields": {
        "type": "string",
        "mutable": false,
        "complexType": {
          "original": "Fields",
          "resolved": "\"day\" | \"month\" | \"year\"",
          "references": {
            "Fields": {
              "location": "local"
            }
          }
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": ""
        },
        "attribute": "fields",
        "reflect": false,
        "defaultValue": "'day'"
      },
      "name": {
        "type": "string",
        "mutable": false,
        "complexType": {
          "original": "string",
          "resolved": "string",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": ""
        },
        "attribute": "name",
        "reflect": false,
        "defaultValue": "''"
      }
    };
  }
  static get states() {
    return {
      "pickerValue": {},
      "height": {},
      "hidden": {},
      "fadeOut": {},
      "isWillLoadCalled": {}
    };
  }
  static get events() {
    return [{
        "method": "onChange",
        "name": "change",
        "bubbles": true,
        "cancelable": true,
        "composed": true,
        "docs": {
          "tags": [],
          "text": ""
        },
        "complexType": {
          "original": "any",
          "resolved": "any",
          "references": {}
        }
      }, {
        "method": "onColumnChange",
        "name": "columnchange",
        "bubbles": true,
        "cancelable": true,
        "composed": true,
        "docs": {
          "tags": [],
          "text": ""
        },
        "complexType": {
          "original": "any",
          "resolved": "any",
          "references": {}
        }
      }, {
        "method": "onCancel",
        "name": "cancel",
        "bubbles": true,
        "cancelable": true,
        "composed": true,
        "docs": {
          "tags": [],
          "text": ""
        },
        "complexType": {
          "original": "any",
          "resolved": "any",
          "references": {}
        }
      }];
  }
  static get elementRef() { return "el"; }
  static get watchers() {
    return [{
        "propName": "mode",
        "methodName": "onPropsChange"
      }, {
        "propName": "value",
        "methodName": "onPropsChange"
      }, {
        "propName": "range",
        "methodName": "onPropsChange"
      }, {
        "propName": "start",
        "methodName": "onPropsChange"
      }, {
        "propName": "end",
        "methodName": "onPropsChange"
      }];
  }
}
//# sourceMappingURL=picker.js.map
