import { Component, Host, h, Element, State, Prop, Event, Method, Watch } from '@stencil/core';
import { i18nDate } from './bal-datepicker.i18n';
import { decreaseYear, isSameDay, isSameMonth, isSameWeek, now, year, getFirstDayOfTheWeek, day, format, month, getLastDayOfMonth, isInRange, isValidDate, } from './bal-datepicker.util';
export class Datepicker {
  constructor() {
    this.isDropdownOpen = false;
    this.pointerMonth = 10;
    this.pointerYear = 2020;
    this.pointerDay = 1;
    /**
     * If `true` the component uses the whole width.
     */
    this.locale = 'en';
    /**
     * The tabindex of the control.
     */
    this.balTabindex = 0;
    /**
     * If `true` the component uses the whole width.
     */
    this.expanded = false;
    /**
     * Set this to `true` when the component is placed on a dark background.
     */
    this.inverted = false;
    /**
     * If `true` the use can only select a date.
     */
    this.readonly = false;
    /**
     * If `true` the component is diabled.
     */
    this.disabled = false;
    /**
     * Defines the placeholder of the input element.
     */
    this.placeholder = '';
    /**
     * Closes the datepicker dropdown after selection
     */
    this.closeOnSelect = true;
    /**
     * If `true` the datepicker only open on click of the icon
     */
    this.triggerIcon = false;
    /**
     * Earliest year available for selection
     */
    this.minYearProp = undefined;
    /**
     * Latest year available for selection
     */
    this.maxYearProp = undefined;
    /**
     * Callback to determine which date in the datepicker should be selectable.
     */
    this.filter = _ => true;
  }
  /**
   * Selects an option
   */
  async select(date) {
    var _a;
    this.value = new Date(date);
    this.updateFromValue();
    this.balChange.emit(this.value);
    if (this.closeOnSelect) {
      await ((_a = this.dropdownElement) === null || _a === void 0 ? void 0 : _a.toggle());
    }
  }
  valueWatcher(newDate, oldDate) {
    if (oldDate === undefined || !isSameDay(newDate, oldDate)) {
      this.updateFromValue();
    }
  }
  componentWillLoad() {
    if (this.value) {
      setTimeout(() => this.updateFromValue(), 0);
    }
  }
  get pointerDate() {
    return new Date(this.pointerYear, this.pointerMonth, this.pointerDay);
  }
  get minYear() {
    return this.minYearProp ? this.minYearProp : decreaseYear(now(), 100);
  }
  get maxYear() {
    return this.maxYearProp ? this.maxYearProp : year(now());
  }
  get years() {
    return Array.from({ length: this.maxYear - this.minYear + 1 }, (_, index) => this.minYear + index);
  }
  get weekDays() {
    const translations = [...i18nDate[this.locale].weekdaysMin];
    translations.push(translations.shift());
    return translations;
  }
  get firstDateOfBox() {
    const date = new Date(this.pointerYear, this.pointerMonth, 1);
    return getFirstDayOfTheWeek(date);
  }
  get calendarGrid() {
    let weekDatePointer = this.firstDateOfBox;
    let dayDatePointer = this.firstDateOfBox;
    let calendar = [];
    do {
      let row = [];
      do {
        row = [
          ...row,
          {
            date: new Date(dayDatePointer),
            dateString: format(dayDatePointer),
            label: day(dayDatePointer).toString(),
            isToday: isSameDay(dayDatePointer, now()),
            isSelected: this.value && isSameDay(dayDatePointer, this.value),
            isDisabled: !this.filter(dayDatePointer),
            isOutdated: this.pointerMonth !== dayDatePointer.getMonth() || !isInRange(dayDatePointer, this.minDate, this.maxDate),
          },
        ];
        dayDatePointer.setDate(dayDatePointer.getDate() + 1);
      } while (isSameWeek(dayDatePointer, weekDatePointer));
      calendar = [...calendar, row];
      weekDatePointer.setDate(weekDatePointer.getDate() + 7);
    } while (isSameMonth(this.pointerDate, dayDatePointer));
    return calendar;
  }
  async onIconClick(event) {
    this.dropdownElement.toggle();
    event.stopPropagation();
  }
  async onInputClick(event) {
    if (!this.triggerIcon) {
      this.dropdownElement.toggle();
    }
    event.stopPropagation();
  }
  onDropdownChange(event) {
    this.isDropdownOpen = event.detail;
    event.stopPropagation();
  }
  onInput(event) {
    const inputValue = event.target.value;
    this.parseAndSetDate(inputValue);
    this.balInput.emit(inputValue);
    event.stopPropagation();
  }
  updateFromValue() {
    if (this.value && isValidDate(this.value)) {
      this.inputElement.value = format(this.value);
      this.pointerYear = year(this.value);
      this.pointerMonth = month(this.value);
      this.pointerDay = day(this.value);
    }
  }
  parseAndSetDate(inputValue, shouldFormat = false) {
    if (inputValue.length >= 8) {
      const parts = inputValue.split('.');
      if (parts.length === 3) {
        const year = parseInt(parts[2], 10);
        const month = parseInt(parts[1], 10) - 1;
        if (parts[2].length === 4 && year >= 1900 && month < 12 && month >= 0) {
          const day = parseInt(parts[0], 10);
          const lastDayOfMonth = getLastDayOfMonth(year, month);
          if (0 < day && day <= lastDayOfMonth) {
            const d = new Date(year, month, day);
            this.value = d;
            this.pointerMonth = month;
            this.pointerYear = year;
            if (shouldFormat) {
              this.inputElement.value = format(d);
            }
          }
        }
      }
    }
  }
  previousMonth() {
    if (this.pointerYear === this.minYear && this.pointerMonth === 0) {
      return;
    }
    if (this.pointerMonth === 0) {
      this.pointerYear = this.pointerYear - 1;
      this.pointerMonth = 11;
    }
    else {
      this.pointerMonth = this.pointerMonth - 1;
    }
  }
  nextMonth() {
    if (this.pointerYear === this.maxYear && this.pointerMonth === 11) {
      return;
    }
    if (this.pointerMonth === 11) {
      this.pointerYear = this.pointerYear + 1;
      this.pointerMonth = 0;
    }
    else {
      this.pointerMonth = this.pointerMonth + 1;
    }
  }
  handleMonthSelect(event) {
    const inputValue = event.target.value;
    this.pointerMonth = parseInt(inputValue, 10);
  }
  handleYearSelect(event) {
    const inputValue = event.target.value;
    this.pointerYear = parseInt(inputValue, 10);
  }
  onClickDateCell(cell) {
    if (!cell.isDisabled) {
      this.select(cell.date);
    }
  }
  onInputKeyDown(event) {
    const allowedKeys = [
      '0',
      '1',
      '2',
      '3',
      '4',
      '5',
      '6',
      '7',
      '8',
      '9',
      '.',
      'Backspace',
      'Enter',
      'ArrowLeft',
      'Left',
      'ArrowRight',
      'Right',
      'Tab',
      'Esc',
      'Escape',
    ];
    if (allowedKeys.indexOf(event.key) < 0) {
      event.preventDefault();
      event.stopPropagation();
    }
  }
  onInputBlur(event) {
    this.balBlur.emit(event);
    this.parseAndSetDate(this.inputElement.value, true);
  }
  render() {
    return (h(Host, { role: "datepicker" },
      h("bal-dropdown", { expanded: this.expanded, onBalCollapse: e => this.onDropdownChange(e), ref: el => (this.dropdownElement = el) },
        this.renderInput(),
        h("div", { class: "datepicker-popup" },
          this.renderHeader(),
          this.renderBody(),
          h("div", { class: "datepicker-footer" },
            h("slot", null))))));
  }
  renderInput() {
    return (h("div", { class: "control has-icons-right", slot: "trigger" },
      h("input", { class: {
          'input': true,
          'clickable': !this.disabled && !this.triggerIcon,
          'is-inverted': this.inverted,
          'is-disabled': this.disabled,
        }, maxlength: "10", autoComplete: "off", disabled: this.disabled, readonly: this.readonly, placeholder: this.placeholder, tabindex: this.balTabindex, onKeyDown: e => this.onInputKeyDown(e), onInput: e => this.onInput(e), onClick: e => this.onInputClick(e), onBlur: e => this.onInputBlur(e), onFocus: e => this.balFocus.emit(e), ref: el => (this.inputElement = el) }),
      h("bal-icon", { class: "datepicker-trigger-icon clickable", size: "medium", "is-right": true, color: this.inverted ? 'white' : 'blue', name: "date", onClick: e => this.onIconClick(e) })));
  }
  renderBody() {
    return (h("section", { class: "datepicker-table" },
      this.renderWeekDayHeader(),
      h("div", { class: "datepicker-body" }, this.calendarGrid.map(row => (h("div", { class: "datepicker-row" }, row.map(cell => (h("div", { "data-date": cell.dateString, onClick: () => this.onClickDateCell(cell), class: [
          'datepicker-cell',
          cell.isToday ? 'is-today' : '',
          cell.isSelected ? 'is-selected' : '',
          cell.isOutdated ? 'is-outdated' : '',
          cell.isDisabled ? 'is-disabled' : '',
          !cell.isOutdated && !cell.isDisabled ? 'is-selectable' : '',
        ].join(' ') }, cell.label)))))))));
  }
  renderWeekDayHeader() {
    return (h("header", { class: "datepicker-header" }, this.weekDays.map(weekday => (h("div", { class: "datepicker-cell" }, weekday)))));
  }
  renderHeader() {
    return (h("header", { class: "datepicker-header" },
      h("div", { class: "pagination field is-centered" },
        h("a", { role: "button", onClick: () => this.previousMonth(), class: "pagination-previous" },
          h("bal-icon", { name: "nav-go-left", size: "large" })),
        h("a", { role: "button", onClick: () => this.nextMonth(), class: "pagination-next" },
          h("bal-icon", { name: "nav-go-right", size: "large" })),
        h("div", { class: "pagination-list" },
          h("div", { class: "field has-addons" },
            h("div", { class: "control month-select" },
              h("span", { class: "select" },
                h("select", { onInput: e => this.handleMonthSelect(e) }, i18nDate[this.locale].months.map((month, index) => (h("option", { value: index, selected: this.pointerMonth === index }, month)))))),
            h("div", { class: "control year-select" },
              h("span", { class: "select" },
                h("select", { onInput: e => this.handleYearSelect(e) }, this.years.map(year => (h("option", { value: year, selected: this.pointerYear === year }, year)))))))))));
  }
  static get is() { return "bal-datepicker"; }
  static get encapsulation() { return "scoped"; }
  static get originalStyleUrls() { return {
    "$": ["bal-datepicker.scss"]
  }; }
  static get styleUrls() { return {
    "$": ["bal-datepicker.css"]
  }; }
  static get properties() { return {
    "locale": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "'en' | 'de' | 'fr' | 'it'",
        "resolved": "\"de\" | \"en\" | \"fr\" | \"it\"",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "If `true` the component uses the whole width."
      },
      "attribute": "locale",
      "reflect": false,
      "defaultValue": "'en'"
    },
    "balTabindex": {
      "type": "number",
      "mutable": false,
      "complexType": {
        "original": "number",
        "resolved": "number",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "The tabindex of the control."
      },
      "attribute": "bal-tabindex",
      "reflect": false,
      "defaultValue": "0"
    },
    "expanded": {
      "type": "boolean",
      "mutable": false,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "If `true` the component uses the whole width."
      },
      "attribute": "expanded",
      "reflect": false,
      "defaultValue": "false"
    },
    "inverted": {
      "type": "boolean",
      "mutable": false,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Set this to `true` when the component is placed on a dark background."
      },
      "attribute": "inverted",
      "reflect": false,
      "defaultValue": "false"
    },
    "readonly": {
      "type": "boolean",
      "mutable": false,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "If `true` the use can only select a date."
      },
      "attribute": "readonly",
      "reflect": false,
      "defaultValue": "false"
    },
    "disabled": {
      "type": "boolean",
      "mutable": false,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "If `true` the component is diabled."
      },
      "attribute": "disabled",
      "reflect": false,
      "defaultValue": "false"
    },
    "placeholder": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Defines the placeholder of the input element."
      },
      "attribute": "placeholder",
      "reflect": false,
      "defaultValue": "''"
    },
    "value": {
      "type": "unknown",
      "mutable": true,
      "complexType": {
        "original": "Date",
        "resolved": "Date",
        "references": {
          "Date": {
            "location": "global"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Selected option value."
      }
    },
    "maxDate": {
      "type": "unknown",
      "mutable": false,
      "complexType": {
        "original": "Date",
        "resolved": "Date",
        "references": {
          "Date": {
            "location": "global"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Latest date available for selection"
      }
    },
    "minDate": {
      "type": "unknown",
      "mutable": false,
      "complexType": {
        "original": "Date",
        "resolved": "Date",
        "references": {
          "Date": {
            "location": "global"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Earliest date available for selection"
      }
    },
    "closeOnSelect": {
      "type": "boolean",
      "mutable": false,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Closes the datepicker dropdown after selection"
      },
      "attribute": "close-on-select",
      "reflect": false,
      "defaultValue": "true"
    },
    "triggerIcon": {
      "type": "boolean",
      "mutable": false,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "If `true` the datepicker only open on click of the icon"
      },
      "attribute": "trigger-icon",
      "reflect": false,
      "defaultValue": "false"
    },
    "minYearProp": {
      "type": "number",
      "mutable": false,
      "complexType": {
        "original": "number | undefined",
        "resolved": "number",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Earliest year available for selection"
      },
      "attribute": "min-year",
      "reflect": false,
      "defaultValue": "undefined"
    },
    "maxYearProp": {
      "type": "number",
      "mutable": false,
      "complexType": {
        "original": "number | undefined",
        "resolved": "number",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Latest year available for selection"
      },
      "attribute": "max-year",
      "reflect": false,
      "defaultValue": "undefined"
    },
    "filter": {
      "type": "unknown",
      "mutable": false,
      "complexType": {
        "original": "BalDateCallback",
        "resolved": "(date: Date) => boolean",
        "references": {
          "BalDateCallback": {
            "location": "import",
            "path": "./bal-datepicker.type"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Callback to determine which date in the datepicker should be selectable."
      },
      "defaultValue": "_ => true"
    }
  }; }
  static get states() { return {
    "isDropdownOpen": {},
    "pointerMonth": {},
    "pointerYear": {},
    "pointerDay": {}
  }; }
  static get events() { return [{
      "method": "balChange",
      "name": "balChange",
      "bubbles": true,
      "cancelable": true,
      "composed": true,
      "docs": {
        "tags": [],
        "text": "Emitted when a option got selected."
      },
      "complexType": {
        "original": "any",
        "resolved": "any",
        "references": {}
      }
    }, {
      "method": "balInput",
      "name": "balInput",
      "bubbles": true,
      "cancelable": true,
      "composed": true,
      "docs": {
        "tags": [],
        "text": "Emitted when a keyboard input occurred."
      },
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      }
    }, {
      "method": "balBlur",
      "name": "balBlur",
      "bubbles": true,
      "cancelable": true,
      "composed": true,
      "docs": {
        "tags": [],
        "text": "Emitted when the input loses focus."
      },
      "complexType": {
        "original": "FocusEvent",
        "resolved": "FocusEvent",
        "references": {
          "FocusEvent": {
            "location": "global"
          }
        }
      }
    }, {
      "method": "balFocus",
      "name": "balFocus",
      "bubbles": true,
      "cancelable": true,
      "composed": true,
      "docs": {
        "tags": [],
        "text": "Emitted when the input has focus."
      },
      "complexType": {
        "original": "FocusEvent",
        "resolved": "FocusEvent",
        "references": {
          "FocusEvent": {
            "location": "global"
          }
        }
      }
    }]; }
  static get methods() { return {
    "select": {
      "complexType": {
        "signature": "(date: Date) => Promise<void>",
        "parameters": [{
            "tags": [],
            "text": ""
          }],
        "references": {
          "Promise": {
            "location": "global"
          },
          "Date": {
            "location": "global"
          }
        },
        "return": "Promise<void>"
      },
      "docs": {
        "text": "Selects an option",
        "tags": []
      }
    }
  }; }
  static get elementRef() { return "element"; }
  static get watchers() { return [{
      "propName": "value",
      "methodName": "valueWatcher"
    }]; }
}
