import { defineComponent, useSlots, computed, createElementBlock, openBlock, normalizeStyle, normalizeClass, unref, createCommentVNode, createElementVNode, renderSlot, createTextVNode, Fragment, renderList, toDisplayString, createBlock, mergeProps, createSlots, withCtx } from 'vue';
import '../../../utils/index.mjs';
import { LlTooltip } from '../../tooltip/index.mjs';
import { heatmapColorThemes, heatmapProps } from './heatmap.mjs';
import { createNamespace } from '../../../utils/create-namespace.mjs';
import { addUnit } from '../../../utils/add-unit.mjs';

"use strict";
const DAY_MS = 24 * 60 * 60 * 1e3;
var _sfc_main = /* @__PURE__ */ defineComponent({
  ...{ name: "LlHeatmap" },
  __name: "heatmap",
  props: heatmapProps,
  setup(__props) {
    const SIZE_MAP = {
      small: {
        rectSize: 10,
        radius: 2,
        fontSize: 12,
        labelWidth: 28
      },
      medium: {
        rectSize: 12,
        radius: 3,
        fontSize: 12,
        labelWidth: 32
      },
      large: {
        rectSize: 15,
        radius: 4,
        fontSize: 13,
        labelWidth: 36
      }
    };
    const props = __props;
    const slots = useSlots();
    const bem = createNamespace("heatmap");
    const showIndicator = computed(() => {
      return props.showColorIndicator || !!slots.indicator;
    });
    const tooltipOptions = computed(() => {
      return {
        show: false,
        placement: "top",
        arrow: true,
        bgColor: void 0,
        textColor: void 0,
        isWhiteBg: false,
        maxWidth: "240px",
        tipEllipsis: false,
        tipEllipsisLine: 1,
        overlayClassName: "",
        overlayStyle: {},
        ellipsis: false,
        width: "",
        containerStyle: {},
        showContainer: false,
        ...props.tooltip
      };
    });
    const tooltipEnabled = computed(() => tooltipOptions.value.show);
    const tooltipBindings = computed(() => {
      const { show, ...rest } = tooltipOptions.value;
      return rest;
    });
    const sizeConfig = computed(() => SIZE_MAP[props.size]);
    const activeColors = computed(() => {
      if (props.activeColors?.length) {
        return props.activeColors;
      }
      if (props.colorTheme) {
        return heatmapColorThemes[props.colorTheme];
      }
      return heatmapColorThemes.green;
    });
    const minimumColor = computed(() => props.minimumColor || "#ebedf0");
    const indicatorColors = computed(() => [
      minimumColor.value,
      ...activeColors.value
    ]);
    const indicatorRowClass = computed(() => {
      return [
        bem.e("indicator-row"),
        bem.em("indicator-row", props.indicatorVerticalPosition),
        bem.em("indicator-row", props.indicatorHorizontalAlign)
      ];
    });
    const cssVars = computed(() => ({
      "--ll-heatmap-rect-size": `${sizeConfig.value.rectSize}px`,
      "--ll-heatmap-radius": `${sizeConfig.value.radius}px`,
      "--ll-heatmap-font-size": `${sizeConfig.value.fontSize}px`,
      "--ll-heatmap-label-width": `${sizeConfig.value.labelWidth}px`,
      "--ll-heatmap-x-gap": addUnit(props.xGap) || "4px",
      "--ll-heatmap-y-gap": addUnit(props.yGap) || "4px"
    }));
    const displaySource = computed(() => {
      if (props.loading) {
        if (props.loadingData?.length) {
          return props.loadingData;
        }
        if (props.data.length) {
          return props.data;
        }
        return createRecentLoadingData();
      }
      return props.data;
    });
    const normalizedData = computed(() => {
      if (!displaySource.value.length) {
        return [];
      }
      const sorted = [...displaySource.value].map((item) => ({
        timestamp: startOfDay(item.timestamp).getTime(),
        value: item.value ?? null
      })).sort((a, b) => a.timestamp - b.timestamp);
      const sourceMap = /* @__PURE__ */ new Map();
      sorted.forEach((item) => {
        sourceMap.set(item.timestamp, item);
      });
      const firstTimestamp = sorted[0].timestamp;
      const lastTimestamp = sorted[sorted.length - 1].timestamp;
      const gridStart = startOfWeek(firstTimestamp, props.firstDayOfWeek);
      const rangeStart = props.fillCalendarLeading ? gridStart : startOfDay(firstTimestamp).getTime();
      const rangeEnd = endOfWeek(lastTimestamp, props.firstDayOfWeek);
      const series = [];
      for (let timestamp = rangeStart; timestamp <= rangeEnd; timestamp += DAY_MS) {
        const sourceItem = sourceMap.get(timestamp);
        const value = sourceItem?.value ?? null;
        const synthetic = !sourceItem;
        series.push({
          timestamp,
          value,
          hidden: props.loading ? value === null : false,
          synthetic
        });
      }
      return series;
    });
    const maxValue = computed(() => {
      return normalizedData.value.reduce((current, item) => {
        const value = typeof item.value === "number" ? item.value : 0;
        return value > current ? value : current;
      }, 0);
    });
    const heatmapMatrix = computed(() => {
      if (!normalizedData.value.length) {
        return [];
      }
      const calendarStart = startOfWeek(
        normalizedData.value[0].timestamp,
        props.firstDayOfWeek
      );
      const weeks = [];
      normalizedData.value.forEach((item) => {
        const rowIndex = getRowIndex(item.timestamp, props.firstDayOfWeek);
        const columnIndex = getColumnIndex(item.timestamp, calendarStart);
        if (!weeks[columnIndex]) {
          weeks[columnIndex] = Array.from({ length: 7 }, () => null);
        }
        weeks[columnIndex][rowIndex] = {
          data: item,
          color: resolveColor(
            item.value,
            maxValue.value,
            activeColors.value,
            minimumColor.value
          ),
          hidden: item.hidden,
          loading: props.loading && !item.hidden
        };
      });
      return weeks;
    });
    const monthLabels = computed(() => {
      let lastMonth = "";
      return heatmapMatrix.value.map((week) => {
        const firstVisibleDay = week.find((item) => item !== null)?.data;
        if (!firstVisibleDay) {
          return "";
        }
        const month = formatMonth(firstVisibleDay.timestamp);
        if (month !== lastMonth) {
          lastMonth = month;
          return month;
        }
        return "";
      });
    });
    const weekLabels = computed(() => {
      const formatter = new Intl.DateTimeFormat(void 0, { weekday: "short" });
      const reference = getReferenceWeekStart(props.firstDayOfWeek);
      return Array.from({ length: 7 }, (_, index) => {
        return formatter.format(addDays(reference, index));
      });
    });
    const getTooltipText = (item) => {
      const dateText = new Date(item.timestamp).toLocaleDateString();
      const value = item.value ?? 0;
      const suffix = props.unit ? ` ${value} ${props.unit}` : ` ${value}`;
      return `${dateText}${suffix}`;
    };
    const getCellClass = (cell) => {
      return [
        bem.e("cell"),
        cell.loading ? bem.is("loading") : "",
        cell.hidden ? bem.is("hidden") : "",
        cell.data.synthetic ? bem.is("synthetic") : ""
      ];
    };
    const getCellStyle = (cell) => {
      return {
        backgroundColor: cell.hidden ? "transparent" : cell.color
      };
    };
    const getCellKey = (cell, weekIndex, dayIndex) => {
      return cell ? `${cell.data.timestamp}-${weekIndex}-${dayIndex}` : `empty-${weekIndex}-${dayIndex}`;
    };
    function startOfDay(timestamp) {
      const date = new Date(timestamp);
      date.setHours(0, 0, 0, 0);
      return date;
    }
    function addDays(date, days) {
      const nextDate = new Date(date);
      nextDate.setDate(nextDate.getDate() + days);
      return nextDate;
    }
    function getJsWeekStart(firstDayOfWeek) {
      return (firstDayOfWeek + 1) % 7;
    }
    function getRowIndex(timestamp, firstDayOfWeek) {
      const weekStart = getJsWeekStart(firstDayOfWeek);
      const day = new Date(timestamp).getDay();
      return (day - weekStart + 7) % 7;
    }
    function startOfWeek(timestamp, firstDayOfWeek) {
      const date = startOfDay(timestamp);
      return addDays(date, -getRowIndex(date.getTime(), firstDayOfWeek)).getTime();
    }
    function endOfWeek(timestamp, firstDayOfWeek) {
      return addDays(new Date(startOfWeek(timestamp, firstDayOfWeek)), 6).getTime();
    }
    function getColumnIndex(timestamp, calendarStart) {
      const current = startOfDay(timestamp).getTime();
      return Math.floor((current - calendarStart) / DAY_MS / 7);
    }
    function resolveColor(value, max, colors, baseColor) {
      if (value === null || value === void 0 || value <= 0 || max <= 0) {
        return baseColor;
      }
      const step = Math.min(colors.length, Math.ceil(value / max * colors.length));
      return colors[Math.max(0, step - 1)] || colors[colors.length - 1] || baseColor;
    }
    function formatMonth(timestamp) {
      return new Intl.DateTimeFormat(void 0, { month: "short" }).format(
        new Date(timestamp)
      );
    }
    function getReferenceWeekStart(firstDayOfWeek) {
      const jsWeekStart = getJsWeekStart(firstDayOfWeek);
      const date = new Date(2024, 0, 7);
      while (date.getDay() !== jsWeekStart) {
        date.setDate(date.getDate() + 1);
      }
      return date;
    }
    function createRecentLoadingData() {
      const today = startOfDay(Date.now());
      const result = [];
      for (let index = 364; index >= 0; index -= 1) {
        result.push({
          timestamp: addDays(today, -index).getTime(),
          value: index % 5 === 0 ? 3 : 1
        });
      }
      return result;
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock(
        "div",
        {
          class: normalizeClass([unref(bem).b(), unref(bem).m(props.size)]),
          style: normalizeStyle(cssVars.value)
        },
        [
          showIndicator.value && props.indicatorVerticalPosition === "top" ? (openBlock(), createElementBlock(
            "div",
            {
              key: 0,
              class: normalizeClass(indicatorRowClass.value)
            },
            [
              renderSlot(_ctx.$slots, "indicator", {}, () => [
                props.showColorIndicator ? (openBlock(), createElementBlock(
                  "div",
                  {
                    key: 0,
                    class: normalizeClass(unref(bem).e("indicator"))
                  },
                  [
                    createElementVNode(
                      "span",
                      {
                        class: normalizeClass(unref(bem).e("indicator-label"))
                      },
                      [
                        renderSlot(_ctx.$slots, "indicator-leading-text", {}, () => [
                          _cache[0] || (_cache[0] = createTextVNode(
                            "\u5C11",
                            -1
                            /* CACHED */
                          ))
                        ])
                      ],
                      2
                      /* CLASS */
                    ),
                    createElementVNode(
                      "div",
                      {
                        class: normalizeClass(unref(bem).e("indicator-cells"))
                      },
                      [
                        (openBlock(true), createElementBlock(
                          Fragment,
                          null,
                          renderList(indicatorColors.value, (color, index) => {
                            return openBlock(), createElementBlock(
                              "div",
                              {
                                key: `indicator-top-${index}`,
                                class: normalizeClass(unref(bem).e("indicator-cell")),
                                style: normalizeStyle({ backgroundColor: color })
                              },
                              null,
                              6
                              /* CLASS, STYLE */
                            );
                          }),
                          128
                          /* KEYED_FRAGMENT */
                        ))
                      ],
                      2
                      /* CLASS */
                    ),
                    createElementVNode(
                      "span",
                      {
                        class: normalizeClass(unref(bem).e("indicator-label"))
                      },
                      [
                        renderSlot(_ctx.$slots, "indicator-trailing-text", {}, () => [
                          _cache[1] || (_cache[1] = createTextVNode(
                            "\u591A",
                            -1
                            /* CACHED */
                          ))
                        ])
                      ],
                      2
                      /* CLASS */
                    )
                  ],
                  2
                  /* CLASS */
                )) : createCommentVNode("v-if", true)
              ])
            ],
            2
            /* CLASS */
          )) : createCommentVNode("v-if", true),
          createElementVNode(
            "div",
            {
              class: normalizeClass(unref(bem).e("content"))
            },
            [
              props.showMonthLabels && heatmapMatrix.value.length ? (openBlock(), createElementBlock(
                "div",
                {
                  key: 0,
                  class: normalizeClass(unref(bem).e("month-row"))
                },
                [
                  props.showWeekLabels ? (openBlock(), createElementBlock(
                    "div",
                    {
                      key: 0,
                      class: normalizeClass(unref(bem).e("month-spacer"))
                    },
                    null,
                    2
                    /* CLASS */
                  )) : createCommentVNode("v-if", true),
                  (openBlock(true), createElementBlock(
                    Fragment,
                    null,
                    renderList(monthLabels.value, (label, index) => {
                      return openBlock(), createElementBlock(
                        "div",
                        {
                          key: `month-${index}`,
                          class: normalizeClass(unref(bem).e("month-label-cell"))
                        },
                        toDisplayString(label),
                        3
                        /* TEXT, CLASS */
                      );
                    }),
                    128
                    /* KEYED_FRAGMENT */
                  ))
                ],
                2
                /* CLASS */
              )) : createCommentVNode("v-if", true),
              createElementVNode(
                "div",
                {
                  class: normalizeClass(unref(bem).e("calendar"))
                },
                [
                  props.showWeekLabels ? (openBlock(), createElementBlock(
                    "div",
                    {
                      key: 0,
                      class: normalizeClass(unref(bem).e("week-labels"))
                    },
                    [
                      (openBlock(true), createElementBlock(
                        Fragment,
                        null,
                        renderList(weekLabels.value, (label, index) => {
                          return openBlock(), createElementBlock(
                            "div",
                            {
                              key: `week-${index}`,
                              class: normalizeClass(unref(bem).e("week-label-cell"))
                            },
                            toDisplayString(label),
                            3
                            /* TEXT, CLASS */
                          );
                        }),
                        128
                        /* KEYED_FRAGMENT */
                      ))
                    ],
                    2
                    /* CLASS */
                  )) : createCommentVNode("v-if", true),
                  createElementVNode(
                    "div",
                    {
                      class: normalizeClass(unref(bem).e("weeks"))
                    },
                    [
                      (openBlock(true), createElementBlock(
                        Fragment,
                        null,
                        renderList(heatmapMatrix.value, (week, weekIndex) => {
                          return openBlock(), createElementBlock(
                            "div",
                            {
                              key: `heatmap-week-${weekIndex}`,
                              class: normalizeClass(unref(bem).e("week-column"))
                            },
                            [
                              (openBlock(true), createElementBlock(
                                Fragment,
                                null,
                                renderList(week, (cell, dayIndex) => {
                                  return openBlock(), createElementBlock(
                                    "div",
                                    {
                                      key: getCellKey(cell, weekIndex, dayIndex),
                                      class: normalizeClass(unref(bem).e("cell-wrap"))
                                    },
                                    [
                                      cell ? (openBlock(), createElementBlock(
                                        Fragment,
                                        { key: 0 },
                                        [
                                          tooltipEnabled.value && !cell.hidden ? (openBlock(), createBlock(unref(LlTooltip), mergeProps({
                                            key: 0,
                                            ref_for: true
                                          }, tooltipBindings.value, {
                                            tip: getTooltipText(cell.data),
                                            "show-container": false
                                          }), createSlots({
                                            default: withCtx(() => [
                                              createElementVNode(
                                                "div",
                                                {
                                                  class: normalizeClass(getCellClass(cell)),
                                                  style: normalizeStyle(getCellStyle(cell))
                                                },
                                                null,
                                                6
                                                /* CLASS, STYLE */
                                              )
                                            ]),
                                            _: 2
                                            /* DYNAMIC */
                                          }, [
                                            unref(slots).tooltip ? {
                                              name: "title",
                                              fn: withCtx(() => [
                                                renderSlot(_ctx.$slots, "tooltip", {
                                                  timestamp: cell.data.timestamp,
                                                  value: cell.data.value
                                                })
                                              ]),
                                              key: "0"
                                            } : void 0
                                          ]), 1040, ["tip"])) : (openBlock(), createElementBlock(
                                            "div",
                                            {
                                              key: 1,
                                              class: normalizeClass(getCellClass(cell)),
                                              style: normalizeStyle(getCellStyle(cell))
                                            },
                                            null,
                                            6
                                            /* CLASS, STYLE */
                                          ))
                                        ],
                                        64
                                        /* STABLE_FRAGMENT */
                                      )) : (openBlock(), createElementBlock(
                                        "div",
                                        {
                                          key: 1,
                                          class: normalizeClass([unref(bem).e("cell"), unref(bem).is("empty")])
                                        },
                                        null,
                                        2
                                        /* CLASS */
                                      ))
                                    ],
                                    2
                                    /* CLASS */
                                  );
                                }),
                                128
                                /* KEYED_FRAGMENT */
                              ))
                            ],
                            2
                            /* CLASS */
                          );
                        }),
                        128
                        /* KEYED_FRAGMENT */
                      ))
                    ],
                    2
                    /* CLASS */
                  )
                ],
                2
                /* CLASS */
              )
            ],
            2
            /* CLASS */
          ),
          unref(slots).footer ? (openBlock(), createElementBlock(
            "div",
            {
              key: 1,
              class: normalizeClass(unref(bem).e("footer"))
            },
            [
              createElementVNode(
                "div",
                {
                  class: normalizeClass(unref(bem).e("footer-left"))
                },
                [
                  renderSlot(_ctx.$slots, "footer")
                ],
                2
                /* CLASS */
              )
            ],
            2
            /* CLASS */
          )) : createCommentVNode("v-if", true),
          showIndicator.value && props.indicatorVerticalPosition === "bottom" ? (openBlock(), createElementBlock(
            "div",
            {
              key: 2,
              class: normalizeClass(indicatorRowClass.value)
            },
            [
              renderSlot(_ctx.$slots, "indicator", {}, () => [
                props.showColorIndicator ? (openBlock(), createElementBlock(
                  "div",
                  {
                    key: 0,
                    class: normalizeClass(unref(bem).e("indicator"))
                  },
                  [
                    createElementVNode(
                      "span",
                      {
                        class: normalizeClass(unref(bem).e("indicator-label"))
                      },
                      [
                        renderSlot(_ctx.$slots, "indicator-leading-text", {}, () => [
                          _cache[2] || (_cache[2] = createTextVNode(
                            "\u5C11",
                            -1
                            /* CACHED */
                          ))
                        ])
                      ],
                      2
                      /* CLASS */
                    ),
                    createElementVNode(
                      "div",
                      {
                        class: normalizeClass(unref(bem).e("indicator-cells"))
                      },
                      [
                        (openBlock(true), createElementBlock(
                          Fragment,
                          null,
                          renderList(indicatorColors.value, (color, index) => {
                            return openBlock(), createElementBlock(
                              "div",
                              {
                                key: `indicator-bottom-${index}`,
                                class: normalizeClass(unref(bem).e("indicator-cell")),
                                style: normalizeStyle({ backgroundColor: color })
                              },
                              null,
                              6
                              /* CLASS, STYLE */
                            );
                          }),
                          128
                          /* KEYED_FRAGMENT */
                        ))
                      ],
                      2
                      /* CLASS */
                    ),
                    createElementVNode(
                      "span",
                      {
                        class: normalizeClass(unref(bem).e("indicator-label"))
                      },
                      [
                        renderSlot(_ctx.$slots, "indicator-trailing-text", {}, () => [
                          _cache[3] || (_cache[3] = createTextVNode(
                            "\u591A",
                            -1
                            /* CACHED */
                          ))
                        ])
                      ],
                      2
                      /* CLASS */
                    )
                  ],
                  2
                  /* CLASS */
                )) : createCommentVNode("v-if", true)
              ])
            ],
            2
            /* CLASS */
          )) : createCommentVNode("v-if", true)
        ],
        6
        /* CLASS, STYLE */
      );
    };
  }
});

export { _sfc_main as default };
//# sourceMappingURL=heatmap.vue2.mjs.map
