import { isArray } from "../../../../../../@vue/shared/dist/shared.esm-bundler.mjs";
import { castArray } from "../../../../utils/arrays.mjs";
import { useLocale } from "../../../../hooks/use-locale/index.mjs";
import { useNamespace } from "../../../../hooks/use-namespace/index.mjs";
import { buildPickerTable } from "../utils.mjs";
import { ref, computed, unref, watch, nextTick } from "vue";
import dayjs from "../../../../../../../_virtual/dayjs.min.mjs";
import flatten from "../../../../../../lodash-es/flatten.mjs";
const isNormalDay = (type = "") => {
  return ["normal", "today"].includes(type);
};
const useBasicDateTable = (props, emit) => {
  const { lang } = useLocale();
  const tbodyRef = ref();
  const currentCellRef = ref();
  const lastRow = ref();
  const lastColumn = ref();
  const tableRows = ref([
    [],
    [],
    [],
    [],
    [],
    []
  ]);
  let focusWithClick = false;
  const firstDayOfWeek = props.date.$locale().weekStart || 7;
  const WEEKS_CONSTANT = props.date.locale("en").localeData().weekdaysShort().map((_) => _.toLowerCase());
  const offsetDay = computed(() => {
    return firstDayOfWeek > 3 ? 7 - firstDayOfWeek : -firstDayOfWeek;
  });
  const startDate = computed(() => {
    const startDayOfMonth = props.date.startOf("month");
    return startDayOfMonth.subtract(startDayOfMonth.day() || 7, "day");
  });
  const WEEKS = computed(() => {
    return WEEKS_CONSTANT.concat(WEEKS_CONSTANT).slice(firstDayOfWeek, firstDayOfWeek + 7);
  });
  const hasCurrent = computed(() => {
    return flatten(unref(rows)).some((row) => {
      return row.isCurrent;
    });
  });
  const days = computed(() => {
    const startOfMonth = props.date.startOf("month");
    return {
      startOfMonthDay: startOfMonth.day() || 7,
      dateCountOfMonth: startOfMonth.daysInMonth(),
      dateCountOfLastMonth: startOfMonth.subtract(1, "month").daysInMonth()
    };
  });
  const selectedDate = computed(() => {
    return props.selectionMode === "dates" ? castArray(props.parsedValue) : [];
  });
  const setDateText = (cell, { count, rowIndex, columnIndex }) => {
    const { startOfMonthDay, dateCountOfMonth, dateCountOfLastMonth } = unref(days);
    const offset = unref(offsetDay);
    if (rowIndex >= 0 && rowIndex <= 1) {
      const numberOfDaysFromPreviousMonth = startOfMonthDay + offset < 0 ? 7 + startOfMonthDay + offset : startOfMonthDay + offset;
      if (columnIndex + rowIndex * 7 >= numberOfDaysFromPreviousMonth) {
        cell.text = count;
        return true;
      } else {
        cell.text = dateCountOfLastMonth - (numberOfDaysFromPreviousMonth - columnIndex % 7) + 1 + rowIndex * 7;
        cell.type = "prev-month";
      }
    } else {
      if (count <= dateCountOfMonth) cell.text = count;
      else {
        cell.text = count - dateCountOfMonth;
        cell.type = "next-month";
      }
      return true;
    }
    return false;
  };
  const setCellMetadata = (cell, { columnIndex, rowIndex }, count) => {
    const { disabledDate, cellClassName } = props;
    const _selectedDate = unref(selectedDate);
    const shouldIncrement = setDateText(cell, {
      count,
      rowIndex,
      columnIndex
    });
    const cellDate = cell.dayjs.toDate();
    cell.selected = _selectedDate.find((d) => d.isSame(cell.dayjs, "day"));
    cell.isSelected = !!cell.selected;
    cell.isCurrent = isCurrent(cell);
    cell.disabled = disabledDate == null ? void 0 : disabledDate(cellDate);
    cell.customClass = cellClassName == null ? void 0 : cellClassName(cellDate);
    return shouldIncrement;
  };
  const setRowMetadata = (row) => {
    if (props.selectionMode === "week") {
      const [start, end] = props.showWeekNumber ? [1, 7] : [0, 6];
      const isActive = isWeekActive(row[start + 1]);
      row[start].inRange = isActive;
      row[start].start = isActive;
      row[end].inRange = isActive;
      row[end].end = isActive;
    }
  };
  const rows = computed(() => {
    const { minDate, maxDate, rangeState, showWeekNumber } = props;
    const offset = unref(offsetDay);
    const rows_ = unref(tableRows);
    const dateUnit = "day";
    let count = 1;
    buildPickerTable({
      row: 6,
      column: 7
    }, rows_, {
      startDate: minDate,
      columnIndexOffset: showWeekNumber ? 1 : 0,
      nextEndDate: rangeState.endDate || maxDate || rangeState.selecting && minDate || null,
      now: dayjs().locale(unref(lang)).startOf(dateUnit),
      unit: dateUnit,
      relativeDateGetter: (idx) => unref(startDate).add(idx - offset, dateUnit),
      setCellMetadata: (...args) => {
        if (setCellMetadata(...args, count)) count += 1;
      },
      setRowMetadata
    });
    if (showWeekNumber) {
      for (let rowIndex = 0; rowIndex < 6; rowIndex++) if (rows_[rowIndex][1].dayjs) rows_[rowIndex][0] = {
        type: "week",
        text: rows_[rowIndex][1].dayjs.week()
      };
    }
    return rows_;
  });
  watch(() => props.date, async () => {
    var _a;
    if ((_a = unref(tbodyRef)) == null ? void 0 : _a.contains(document.activeElement)) {
      await nextTick();
      await focus();
    }
  });
  const focus = async () => {
    var _a;
    return (_a = unref(currentCellRef)) == null ? void 0 : _a.focus();
  };
  const isCurrent = (cell) => {
    return props.selectionMode === "date" && isNormalDay(cell.type) && cellMatchesDate(cell, props.parsedValue);
  };
  const cellMatchesDate = (cell, date) => {
    if (!date) return false;
    return dayjs(date).locale(unref(lang)).isSame(props.date.date(Number(cell.text)), "day");
  };
  const getDateOfCell = (row, column) => {
    const startOfMonthDay = unref(days).startOfMonthDay;
    const offset = unref(offsetDay);
    const numberOfDaysFromPreviousMonth = startOfMonthDay + offset < 0 ? 7 + startOfMonthDay + offset : startOfMonthDay + offset;
    const offsetFromStart = row * 7 + (column - (props.showWeekNumber ? 1 : 0));
    return props.date.startOf("month").subtract(numberOfDaysFromPreviousMonth, "day").add(offsetFromStart, "day");
  };
  const handleMouseMove = (event) => {
    var _a;
    if (!props.rangeState.selecting) return;
    let target = event.target;
    if (target.tagName === "SPAN") target = (_a = target.parentNode) == null ? void 0 : _a.parentNode;
    if (target.tagName === "DIV") target = target.parentNode;
    if (target.tagName !== "TD") return;
    const row = target.parentNode.rowIndex - 1;
    const column = target.cellIndex;
    if (unref(rows)[row][column].disabled) return;
    if (row !== unref(lastRow) || column !== unref(lastColumn)) {
      lastRow.value = row;
      lastColumn.value = column;
      emit("changerange", {
        selecting: true,
        endDate: getDateOfCell(row, column)
      });
    }
  };
  const isSelectedCell = (cell) => {
    return !unref(hasCurrent) && (cell == null ? void 0 : cell.text) === 1 && isNormalDay(cell.type) || cell.isCurrent;
  };
  const handleFocus = (event) => {
    if (focusWithClick || unref(hasCurrent) || props.selectionMode !== "date") return;
    handlePickDate(event, true);
  };
  const handleMouseDown = (event) => {
    if (!event.target.closest("td")) return;
    focusWithClick = true;
  };
  const handleMouseUp = (event) => {
    if (!event.target.closest("td")) return;
    focusWithClick = false;
  };
  const handleRangePick = (newDate) => {
    if (!props.rangeState.selecting || !props.minDate) {
      emit("pick", {
        minDate: newDate,
        maxDate: null
      });
      emit("select", true);
    } else {
      if (newDate >= props.minDate) emit("pick", {
        minDate: props.minDate,
        maxDate: newDate
      });
      else emit("pick", {
        minDate: newDate,
        maxDate: props.minDate
      });
      emit("select", false);
    }
  };
  const handleWeekPick = (newDate) => {
    const weekNumber = newDate.week();
    const value = `${newDate.year()}w${weekNumber}`;
    emit("pick", {
      year: newDate.year(),
      week: weekNumber,
      value,
      date: newDate.startOf("week")
    });
  };
  const handleDatesPick = (newDate, selected) => {
    emit("pick", selected ? castArray(props.parsedValue).filter((d) => (d == null ? void 0 : d.valueOf()) !== newDate.valueOf()) : castArray(props.parsedValue).concat([newDate]));
  };
  const handlePickDate = (event, isKeyboardMovement = false) => {
    if (props.disabled) return;
    const target = event.target.closest("td");
    if (!target) return;
    const row = target.parentNode.rowIndex - 1;
    const column = target.cellIndex;
    const cell = unref(rows)[row][column];
    if (cell.disabled || cell.type === "week") return;
    const newDate = getDateOfCell(row, column);
    switch (props.selectionMode) {
      case "range":
        handleRangePick(newDate);
        break;
      case "date":
        emit("pick", newDate, isKeyboardMovement);
        break;
      case "week":
        handleWeekPick(newDate);
        break;
      case "dates":
        handleDatesPick(newDate, !!cell.selected);
        break;
    }
  };
  const isWeekActive = (cell) => {
    if (props.selectionMode !== "week") return false;
    let newDate = props.date.startOf("day");
    if (cell.type === "prev-month") newDate = newDate.subtract(1, "month");
    if (cell.type === "next-month") newDate = newDate.add(1, "month");
    newDate = newDate.date(Number.parseInt(cell.text, 10));
    if (props.parsedValue && !isArray(props.parsedValue)) {
      const dayOffset = (props.parsedValue.day() - firstDayOfWeek + 7) % 7 - 1;
      return props.parsedValue.subtract(dayOffset, "day").isSame(newDate, "day");
    }
    return false;
  };
  return {
    WEEKS,
    rows,
    tbodyRef,
    currentCellRef,
    focus,
    isCurrent,
    isWeekActive,
    isSelectedCell,
    handlePickDate,
    handleMouseUp,
    handleMouseDown,
    handleMouseMove,
    handleFocus
  };
};
const useBasicDateTableDOM = (props, { isCurrent, isWeekActive }) => {
  const ns = useNamespace("date-table");
  const { t } = useLocale();
  const tableKls = computed(() => [ns.b(), ns.is("week-mode", props.selectionMode === "week" && !props.disabled)]);
  const tableLabel = computed(() => t("el.datepicker.dateTablePrompt"));
  const getCellClasses = (cell) => {
    const classes = [];
    if (isNormalDay(cell.type) && !cell.disabled) {
      classes.push("available");
      if (cell.type === "today") classes.push("today");
    } else classes.push(cell.type);
    if (isCurrent(cell)) classes.push("current");
    if (cell.inRange && (isNormalDay(cell.type) || props.selectionMode === "week")) {
      classes.push("in-range");
      if (cell.start) classes.push("start-date");
      if (cell.end) classes.push("end-date");
    }
    if (cell.disabled || props.disabled) classes.push("disabled");
    if (cell.selected) classes.push("selected");
    if (cell.customClass) classes.push(cell.customClass);
    return classes.join(" ");
  };
  const getRowKls = (cell) => [ns.e("row"), { current: isWeekActive(cell) }];
  return {
    tableKls,
    tableLabel,
    weekHeaderClass: ns.e("week-header"),
    getCellClasses,
    getRowKls,
    t
  };
};
export {
  useBasicDateTable,
  useBasicDateTableDOM
};
