/* COPYRIGHT Esri - https://js.arcgis.com/5.1/LICENSE.txt */
import { c as customElement } from "../../chunks/runtime.js";
import { ref } from "lit/directives/ref.js";
import { keyed } from "lit/directives/keyed.js";
import { css, html } from "lit";
import { LitElement, createEvent, safeClassMap } from "@arcgis/lumina";
import { i as inRange, b as dateFromRange, s as sameDate, h as hasSameMonthAndYear, c as getFirstValidDateInMonth, n as nextMonth } from "../../chunks/date.js";
const CSS = {
  calendar: "calendar",
  calendarContainer: "calendar-container",
  calendarStart: "calendar--start",
  currentDay: "current-day",
  dayContainer: "day-container",
  month: "month",
  noncurrent: "noncurrent",
  weekDays: "week-days",
  weekHeader: "week-header",
  weekHeaderContainer: "week-header-container"
};
const styles = css`:host([hidden]){display:none}[hidden]{display:none}.calendar-container{display:flex;inline-size:100%}:host([range][layout=vertical]) .calendar-container{flex-direction:column}.calendar{inline-size:100%}.week-header-container{display:flex;block-size:16px;padding-inline:var(--calcite-spacing-sm);padding-block:var(--calcite-spacing-md)}.week-header{display:flex;align-items:center;justify-content:center;text-align:center;font-size:var(--calcite-font-size-relative-sm);line-height:var(--calcite-font-line-height-sm);font-weight:var(--calcite-font-weight-bold);inline-size:14.2857142857%;color:var(--calcite-date-picker-week-header-text-color, var(--calcite-color-text-2))}.day-container{display:flex;inline-size:100%;min-inline-size:0px;justify-content:center}.day-container calcite-date-picker-day{inline-size:100%}.week-days{display:grid;grid-template-columns:repeat(7,1fr);grid-auto-rows:1fr;padding-inline:var(--calcite-spacing-sm);padding-block-end:var(--calcite-spacing-sm)}.month-header{display:flex;inline-size:100%;justify-content:space-between}.month{display:flex;inline-size:100%;flex-direction:column;justify-content:space-between}.day{font-size:var(--calcite-font-size)}:host([scale=s]) .week-days{padding-inline:var(--calcite-spacing-xs);padding-block-end:var(--calcite-spacing-xs)}:host([scale=s]) .week-header-container{padding-inline:var(--calcite-spacing-xs);padding-block:var(--calcite-spacing-sm)}:host([scale=s]) .day{font-size:var(--calcite-font-size-sm)}:host([scale=l]) .week-header{font-size:var(--calcite-font-size-relative-base);line-height:var(--calcite-font-line-height-base)}:host([scale=l]) .week-days{padding-inline:var(--calcite-spacing-md);padding-block-end:var(--calcite-spacing-md)}:host([scale=l]) .week-header-container{padding-inline:var(--calcite-spacing-md);padding-block:var(--calcite-spacing-md-plus)}:host([scale=l]) .day{font-size:var(--calcite-font-size-md)}.calendar--start{border-width:0px;border-style:solid;border-color:var(--calcite-date-picker-range-calendar-divider-color, var(--calcite-color-border-1))}:host([range][layout=horizontal][calendars="2"]) .calendar--start{border-inline-end-width:var(--calcite-border-width-sm)}:host([range][layout=vertical][calendars="2"]) .calendar--start{border-block-end-width:var(--calcite-border-width-sm)}.noncurrent{pointer-events:none;opacity:0}`;
const DAYS_PER_WEEK = 7;
const DAYS_MAXIMUM_INDEX = 6;
const NUM_DAYS_TO_DISPLAY = 42;
class DatePickerMonth extends LitElement {
  constructor() {
    super();
    this.storeDayRef = (el) => {
      if (el?.active && this.activeFocus) {
        el.setFocus();
      }
    };
    this.activeDate = /* @__PURE__ */ new Date();
    this.calendars = 2;
    this.range = false;
    this.calciteInternalDatePickerDayHover = createEvent({ cancelable: false });
    this.calciteInternalDatePickerDaySelect = createEvent({ cancelable: false });
    this.calciteInternalDatePickerMonthActiveDateChange = createEvent({ cancelable: false });
    this.calciteInternalDatePickerMonthChange = createEvent({ cancelable: false });
    this.calciteInternalDatePickerMonthMouseOut = createEvent({ cancelable: false });
    this.listen("pointerout", this.pointerOutHandler);
    this.listen("focusout", this.disableActiveFocus);
  }
  static {
    this.properties = { focusedDate: [16, {}, { state: true }], activeDate: [0, {}, { attribute: false }], calendars: [11, {}, { type: Number, reflect: true }], dateTimeFormat: [0, {}, { attribute: false }], endDate: [0, {}, { attribute: false }], headingLevel: [11, {}, { type: Number, reflect: true }], hoverRange: [0, {}, { attribute: false }], layout: [3, {}, { reflect: true }], localeData: [0, {}, { attribute: false }], max: [0, {}, { attribute: false }], messages: [0, {}, { attribute: false }], min: [0, {}, { attribute: false }], monthStyle: 1, range: [7, {}, { reflect: true, type: Boolean }], scale: [3, {}, { reflect: true }], selectedDate: [0, {}, { attribute: false }], startDate: [0, {}, { attribute: false }] };
  }
  static {
    this.styles = styles;
  }
  load() {
    this.focusedDate = this.selectedDate || this.activeDate;
  }
  willUpdate(changes) {
    if (changes.has("activeDate")) {
      this.updateFocusedDateWithActive(this.activeDate);
    }
    if (changes.has("selectedDate")) {
      this.focusedDate = this.selectedDate;
    }
  }
  updateFocusedDateWithActive(newActiveDate) {
    if (!this.selectedDate) {
      this.focusedDate = inRange(newActiveDate, this.min, this.max) ? newActiveDate : dateFromRange(newActiveDate, this.min, this.max);
    }
  }
  keyDownHandler(event) {
    if (event.defaultPrevented) {
      return;
    }
    const isRTL = this.el.dir === "rtl";
    const dateValue = event.target.value;
    switch (event.key) {
      case "ArrowUp":
        event.preventDefault();
        this.addDays(-7, dateValue);
        break;
      case "ArrowRight":
        event.preventDefault();
        this.addDays(isRTL ? -1 : 1, dateValue);
        break;
      case "ArrowDown":
        event.preventDefault();
        this.addDays(7, dateValue);
        break;
      case "ArrowLeft":
        event.preventDefault();
        this.addDays(isRTL ? 1 : -1, dateValue);
        break;
      case "PageUp":
        event.preventDefault();
        this.addMonths(-1, dateValue);
        break;
      case "PageDown":
        event.preventDefault();
        this.addMonths(1, dateValue);
        break;
      case "Home":
        event.preventDefault();
        this.activeDate.setDate(1);
        this.addDays(0, dateValue);
        break;
      case "End":
        event.preventDefault();
        this.activeDate.setDate(new Date(this.activeDate.getFullYear(), this.activeDate.getMonth() + 1, 0).getDate());
        this.addDays(0, dateValue);
        break;
      case "Enter":
      case " ":
        event.preventDefault();
        break;
      case "Tab":
        this.activeFocus = false;
    }
  }
  disableActiveFocus() {
    this.activeFocus = false;
  }
  pointerOutHandler() {
    this.calciteInternalDatePickerMonthMouseOut.emit();
  }
  addMonths(step, targetDate) {
    const nextDate = new Date(targetDate);
    nextDate.setMonth(targetDate.getMonth() + step);
    this.calciteInternalDatePickerMonthActiveDateChange.emit(dateFromRange(nextDate, this.min, this.max));
    this.focusedDate = dateFromRange(nextDate, this.min, this.max);
    this.activeFocus = true;
    this.calciteInternalDatePickerDayHover.emit(nextDate);
  }
  addDays(step = 0, targetDate) {
    const nextDate = new Date(targetDate);
    nextDate.setDate(targetDate.getDate() + step);
    this.calciteInternalDatePickerMonthActiveDateChange.emit(dateFromRange(nextDate, this.min, this.max));
    this.focusedDate = dateFromRange(nextDate, this.min, this.max);
    this.activeFocus = true;
    this.calciteInternalDatePickerDayHover.emit(nextDate);
  }
  getPreviousMonthDays(month, year, startOfWeek) {
    const lastDate = new Date(year, month, 0);
    const date = lastDate.getDate();
    const startDay = lastDate.getDay();
    const days = [];
    if (startDay === (startOfWeek + DAYS_MAXIMUM_INDEX) % DAYS_PER_WEEK) {
      return days;
    }
    if (startDay === startOfWeek) {
      return [date];
    }
    for (let i = (DAYS_PER_WEEK + startDay - startOfWeek) % DAYS_PER_WEEK; i >= 0; i--) {
      days.push(date - i);
    }
    return days;
  }
  getCurrentMonthDays(month, year) {
    const num = new Date(year, month + 1, 0).getDate();
    const days = [];
    for (let i = 0; i < num; i++) {
      days.push(i + 1);
    }
    return days;
  }
  getNextMonthDays(month, year, startOfWeek) {
    const endDay = new Date(year, month + 1, 0).getDay();
    const days = [];
    if (endDay === (startOfWeek + DAYS_MAXIMUM_INDEX) % DAYS_PER_WEEK) {
      return days;
    }
    for (let i = 0; i < (DAYS_MAXIMUM_INDEX - (endDay - startOfWeek)) % DAYS_PER_WEEK; i++) {
      days.push(i + 1);
    }
    return days;
  }
  betweenSelectedRange(date) {
    return !!(this.startDate && this.endDate && date > this.startDate && date < this.endDate && !this.isRangeHover(date));
  }
  isSelected(date) {
    return !!(sameDate(date, this.selectedDate) || this.startDate && sameDate(date, this.startDate) || this.endDate && sameDate(date, this.endDate));
  }
  isStartOfRange(date) {
    return !!(this.startDate && !sameDate(this.startDate, this.endDate) && sameDate(this.startDate, date) && !this.isEndOfRange(date));
  }
  isEndOfRange(date) {
    return !!(this.endDate && !sameDate(this.startDate, this.endDate) && sameDate(this.endDate, date) || !this.endDate && this.hoverRange && sameDate(this.startDate, this.hoverRange.end) && sameDate(date, this.hoverRange.end));
  }
  dayHover(event) {
    const target = event.target;
    if (target.disabled) {
      this.calciteInternalDatePickerMonthMouseOut.emit();
    } else {
      this.calciteInternalDatePickerDayHover.emit(target.value);
    }
    event.stopPropagation();
  }
  daySelect(event) {
    const target = event.target;
    this.activeFocus = false;
    this.calciteInternalDatePickerDaySelect.emit(target.value);
    event.stopPropagation();
  }
  isFocusedOnStart() {
    return this.hoverRange?.focused === "start";
  }
  isHoverInRange() {
    if (!this.hoverRange || !this.startDate) {
      return false;
    }
    const { start, end } = this.hoverRange;
    const isStartFocused = this.isFocusedOnStart();
    const isEndAfterStart = this.startDate && end > this.startDate;
    const isEndBeforeEnd = this.endDate && end < this.endDate;
    const isStartAfterStart = this.startDate && start > this.startDate;
    const isStartBeforeEnd = this.endDate && start < this.endDate;
    const isEndDateAfterStartAndBeforeEnd = !isStartFocused && this.startDate && isEndAfterStart && (!this.endDate || isEndBeforeEnd);
    const isStartDateBeforeEndAndAfterStart = isStartFocused && this.startDate && isStartAfterStart && isStartBeforeEnd;
    return isEndDateAfterStartAndBeforeEnd || isStartDateBeforeEndAndAfterStart;
  }
  isRangeHover(date) {
    if (!this.hoverRange) {
      return false;
    }
    const { start, end } = this.hoverRange;
    const isStartFocused = this.isFocusedOnStart();
    const insideRange = this.isHoverInRange();
    const isDateBeforeStartDateAndAfterStart = date > start && date < this.startDate;
    const isDateAfterEndDateAndBeforeEnd = date < end && date > this.endDate;
    const isDateBeforeEndDateAndAfterEnd = date > end && date < this.endDate;
    const isDateAfterStartDateAndBeforeStart = date < start && date > this.startDate;
    const isDateAfterStartDateAndBeforeEnd = date < end && date > this.startDate;
    const isDateBeforeEndDateAndAfterStart = date > start && date < this.endDate;
    const hasBothStartAndEndDate = this.startDate && this.endDate;
    if (insideRange) {
      if (hasBothStartAndEndDate) {
        return isStartFocused ? date < this.endDate && (isDateAfterStartDateAndBeforeStart || isDateBeforeStartDateAndAfterStart) : isDateBeforeEndDateAndAfterEnd || isDateAfterEndDateAndBeforeEnd;
      } else if (this.startDate && !this.endDate) {
        return isStartFocused ? isDateBeforeStartDateAndAfterStart : isDateAfterStartDateAndBeforeEnd;
      } else if (!this.startDate && this.endDate) {
        return isStartFocused ? isDateBeforeEndDateAndAfterStart : isDateAfterEndDateAndBeforeEnd;
      }
    } else {
      if (hasBothStartAndEndDate) {
        return isStartFocused ? isDateBeforeStartDateAndAfterStart : isDateAfterEndDateAndBeforeEnd;
      }
    }
  }
  getDays(prevMonthDays, currMonthDays, nextMonthDays, position = "start") {
    let month = this.activeDate.getMonth();
    const nextMonth2 = month + 1;
    month = position === "end" ? nextMonth2 : month;
    const year = this.activeDate.getFullYear();
    const days = [
      ...prevMonthDays.map((day) => {
        return {
          active: false,
          day,
          date: new Date(year, month - 1, day)
        };
      }),
      ...currMonthDays.map((day) => {
        const date = new Date(year, month, day);
        const isCurrentDay = sameDate(date, /* @__PURE__ */ new Date());
        const active = this.focusedDate && this.focusedDate !== this.startDate && this.focusedDate !== this.endDate ? sameDate(date, this.focusedDate) : sameDate(date, this.startDate) || sameDate(date, this.endDate);
        return {
          active,
          currentMonth: true,
          currentDay: isCurrentDay,
          day,
          date
        };
      }),
      ...nextMonthDays.map((day) => {
        return {
          active: false,
          day,
          date: new Date(year, nextMonth2, day)
        };
      })
    ];
    return days;
  }
  monthHeaderSelectChange(event) {
    const date = new Date(event.detail);
    const target = event.target;
    this.updateFocusableDate(date);
    event.stopPropagation();
    this.calciteInternalDatePickerMonthChange.emit({ date, position: target.position });
  }
  updateFocusableDate(date) {
    if (!this.selectedDate || !this.range) {
      this.focusedDate = this.getFirstValidDateOfMonth(date);
    } else if (this.selectedDate && this.range) {
      if (!hasSameMonthAndYear(this.startDate, date) || !hasSameMonthAndYear(this.endDate, date)) {
        this.focusedDate = this.getFirstValidDateOfMonth(date);
      }
    }
  }
  getFirstValidDateOfMonth(date) {
    return date.getDate() === 1 ? date : getFirstValidDateInMonth(date, this.min, this.max);
  }
  render() {
    const month = this.activeDate.getMonth();
    const year = this.activeDate.getFullYear();
    const startOfWeek = this.localeData.weekStart % 7;
    const { abbreviated, short, narrow } = this.localeData.days;
    const weekDays = this.scale === "s" ? narrow || short || abbreviated : short || abbreviated || narrow;
    const adjustedWeekDays = [...weekDays.slice(startOfWeek, 7), ...weekDays.slice(0, startOfWeek)];
    const curMonDays = this.getCurrentMonthDays(month, year);
    const prevMonDays = this.getPreviousMonthDays(month, year, startOfWeek);
    const nextMonDays = this.getNextMonthDays(month, year, startOfWeek);
    const numDaysDisplayed = curMonDays.length + prevMonDays.length + nextMonDays.length;
    if (numDaysDisplayed < NUM_DAYS_TO_DISPLAY) {
      const initialDay = nextMonDays.length ? nextMonDays[nextMonDays.length - 1] : 0;
      for (let i = 1; i <= NUM_DAYS_TO_DISPLAY - numDaysDisplayed; i++) {
        nextMonDays.push(initialDay + i);
      }
    }
    const nextMonth2 = month + 1;
    const endCalendarPrevMonDays = this.getPreviousMonthDays(nextMonth2, year, startOfWeek);
    const endCalendarCurrMonDays = this.getCurrentMonthDays(nextMonth2, year);
    const endCalendarNextMonDays = this.getNextMonthDays(nextMonth2, year, startOfWeek);
    const days = this.getDays(prevMonDays, curMonDays, nextMonDays);
    const nextMonthDays = this.getDays(endCalendarPrevMonDays, endCalendarCurrMonDays, endCalendarNextMonDays, "end");
    return html`<div class=${safeClassMap({ [CSS.calendarContainer]: true })} role=grid>${this.renderCalendar(adjustedWeekDays, days)}${this.range && this.calendars === 2 && this.renderCalendar(adjustedWeekDays, nextMonthDays, true) || ""}</div>`;
  }
  renderDateDay({ active, currentMonth, currentDay, date, day }, key) {
    const isDateInRange = inRange(date, this.min, this.max);
    return keyed(key, html`<div class=${safeClassMap({ [CSS.dayContainer]: true })} role=gridcell><calcite-date-picker-day .active=${active} class=${safeClassMap({
      [CSS.currentDay]: currentDay,
      [CSS.noncurrent]: this.range && this.calendars === 2 && !currentMonth
    })} .currentMonth=${currentMonth} .dateTimeFormat=${this.dateTimeFormat} .day=${day} .disabled=${!isDateInRange} .endOfRange=${this.isEndOfRange(date)} .highlighted=${this.betweenSelectedRange(date)} @calciteInternalDayHover=${this.dayHover} @calciteInternalDaySelect=${this.daySelect} .range=${!!this.startDate && !!this.endDate && !sameDate(this.startDate, this.endDate)} .rangeHover=${isDateInRange && this.isRangeHover(date)} .scale=${this.scale} .selected=${this.isSelected(date)} .startOfRange=${this.isStartOfRange(date)} .value=${date} ${ref(this.storeDayRef)}></calcite-date-picker-day></div>`);
  }
  renderCalendar(weekDays, days, isEndCalendar = false) {
    return html`<div class=${safeClassMap({
      [CSS.calendar]: true,
      [CSS.calendarStart]: !isEndCalendar
    })}><calcite-date-picker-month-header .activeDate=${isEndCalendar ? nextMonth(this.activeDate) : this.activeDate} .headingLevel=${this.headingLevel} .localeData=${this.localeData} .max=${this.max} .messages=${this.messages} .min=${this.min} .monthStyle=${this.monthStyle} @calciteInternalDatePickerMonthHeaderSelectChange=${this.monthHeaderSelectChange} .position=${isEndCalendar ? "end" : this.range && this.calendars === 2 ? "start" : null} .scale=${this.scale} .selectedDate=${this.selectedDate}></calcite-date-picker-month-header>${this.renderMonthCalendar(weekDays, days, isEndCalendar)}</div>`;
  }
  renderMonthCalendar(weekDays, days, isEndCalendar = false) {
    const endCalendarStartIndex = 50;
    return html`<div class=${safeClassMap({ [CSS.month]: true })} @keydown=${this.keyDownHandler}><div class=${safeClassMap({ [CSS.weekHeaderContainer]: true })} role=row>${weekDays.map((weekday) => html`<span class=${safeClassMap({ [CSS.weekHeader]: true })} role=columnheader>${weekday}</span>`)}</div><div class=${safeClassMap({ [CSS.weekDays]: true })} role=row>${days.map((day, index) => this.renderDateDay(day, isEndCalendar ? endCalendarStartIndex + index : index))}</div></div>`;
  }
}
customElement("calcite-date-picker-month", DatePickerMonth);
export {
  DatePickerMonth
};
