<template>
  <section class="w-full h-full">
    <p class="h2 ml-1 mb-2">Activity Select</p>
    <div
      class="flex flex-row justify-between items-start gap-4 w-full h-[calc(100%_-_48px)]"
    >
      <!-- Attribute Name -->
      <div
        class="basis-1/3 bg-neutral-10 border border-neutral-300 rounded-xl px-4 pb-4 w-full h-full relative text-sm"
      >
        <p class="h2 my-2">
          Attribute Name ({{ attTotal }})<span
            class="material-symbols-outlined !text-sm align-middle ml-2 cursor-pointer"
            v-tooltip.bottom="tooltip.attributeName"
            >info</span
          >
        </p>
        <div
          class="overflow-y-auto overflow-x-auto scrollbar -mx-2 h-[calc(100%_-_56px)]"
        >
          <DataTable
            v-model:selection="selectedAttName"
            :value="filterAttrs"
            dataKey="key"
            breakpoint="0"
            :tableClass="tableClass"
            @row-select="switchAttNameRadio"
          >
            <Column
              selectionMode="single"
              :headerClass="headerModeClass"
              :bodyClass="bodyModeClass"
            ></Column>
            <Column
              field="key"
              header="Attribute"
              :headerClass="headerClass"
              :bodyClass="bodyClass"
              sortable
            >
              <template #body="slotProps">
                <div
                  :title="slotProps.data.key"
                  class="whitespace-nowrap break-keep overflow-hidden text-ellipsis w-full"
                >
                  {{ slotProps.data.key }}
                </div>
              </template>
            </Column>
          </DataTable>
        </div>
      </div>
      <!-- Range Selection -->
      <div
        class="basis-2/3 bg-neutral-10 border border-neutral-300 rounded-xl px-4 w-full h-full"
      >
        <div class="flex justify-between items-center my-2 flex-wrap">
          <p class="h2">Range Selection {{ attRangeTotal }}</p>
        </div>
        <div
          class="overflow-y-auto overflow-x-auto scrollbar -mx-2 w-full h-[calc(100%_-_70px)]"
        >
          <!-- type: boolean -->
          <div v-if="selectedAttName.type === 'boolean'" class="w-full">
            <DataTable
              v-model:selection="selectedAttRange"
              :value="attRangeData"
              dataKey="id"
              breakpoint="0"
              :tableClass="tableClass"
              @row-select="onRowSelectionChange"
            >
              <ColumnGroup type="header">
                <Row>
                  <Column
                    selectionMode="single"
                    :headerClass="headerModeClass"
                  ></Column>
                  <Column
                    field="value"
                    header="Value"
                    :headerClass="headerClass"
                    sortable
                  />
                  <Column
                    field="freq"
                    header="Occurrences"
                    :headerClass="headerClass"
                    sortable
                    :colspan="3"
                  />
                </Row>
              </ColumnGroup>
              <Column
                selectionMode="single"
                :bodyClass="bodyModeClass"
              ></Column>
              <Column field="label" header="Activity" :bodyClass="bodyClass">
                <template #body="slotProps">
                  <div
                    :title="slotProps.data.label"
                    class="whitespace-nowrap break-keep overflow-hidden text-ellipsis w-full"
                  >
                    {{ slotProps.data.label }}
                  </div>
                </template>
              </Column>
              <Column
                header="Progress"
                bodyClass="!py-2 !border-0 min-w-[96px]"
              >
                <template #body="slotProps">
                  <div
                    class="h-4 w-full bg-neutral-300 rounded-sm overflow-hidden"
                  >
                    <div
                      class="h-full bg-primary"
                      :style="progressWidth(slotProps.data.occ_progress_bar)"
                    ></div>
                  </div>
                </template>
              </Column>
              <Column
                field="occ_value"
                header="Occurrences"
                bodyClass="!text-right !py-2 !border-0"
              ></Column>
              <Column
                field="occ_ratio"
                header="Occurrence Ratio"
                bodyClass="!text-right !py-2 !border-0"
              ></Column>
            </DataTable>
          </div>
          <!-- type: string -->
          <div v-else-if="selectedAttName.type === 'string'" class="w-full">
            <DataTable
              v-model:selection="selectedAttRange"
              :value="attRangeData"
              dataKey="id"
              breakpoint="0"
              tableClass="w-full !border-separate !border-spacing-x-2 !table-auto text-sm"
              @row-select="onRowSelectionChange"
              @row-unselect="onRowSelectionChange"
              @row-select-all="onRowSelectAll($event)"
              @row-unselect-all="onRowUnelectAll"
            >
              <ColumnGroup type="header">
                <Row>
                  <Column
                    selectionMode="multiple"
                    :headerClass="headerModeClass"
                  ></Column>
                  <Column
                    field="value"
                    header="Value"
                    :headerClass="headerClass"
                    sortable
                  />
                  <Column
                    field="freq"
                    header="Occurrences"
                    :headerClass="headerClass"
                    sortable
                    :colspan="3"
                  />
                </Row>
              </ColumnGroup>
              <Column
                selectionMode="multiple"
                :bodyClass="bodyModeClass"
              ></Column>
              <Column field="value" header="Activity" :bodyClass="bodyClass">
                <template #body="slotProps">
                  <div
                    :title="slotProps.data.value"
                    class="whitespace-nowrap break-keep overflow-hidden text-ellipsis w-full"
                  >
                    {{ slotProps.data.value }}
                  </div>
                </template>
              </Column>
              <Column
                header="Progress"
                bodyClass="!py-2 !border-0 min-w-[96px]"
              >
                <template #body="slotProps">
                  <div
                    class="h-4 w-full bg-neutral-300 rounded-sm overflow-hidden"
                  >
                    <div
                      class="h-full bg-primary"
                      :style="progressWidth(slotProps.data.occ_progress_bar)"
                    ></div>
                  </div>
                </template>
              </Column>
              <Column
                field="occ_value"
                header="Occurrences"
                bodyClass="!text-right !py-2 !border-0"
              ></Column>
              <Column
                field="occ_ratio"
                header="Occurrence Ratio"
                bodyClass="!text-right !py-2 !border-0"
              ></Column>
            </DataTable>
          </div>
          <!-- type: value -->
          <div
            v-else-if="valueTypes.has(selectedAttName.type)"
            class="space-y-2 text-sm w-full"
          >
            <!-- Chart.js -->
            <div class="h-3/5 relative">
              <Chart
                type="line"
                :data="chartData"
                :options="chartOptions"
                class="h-30rem"
                id="chartCanvasId"
              />
              <div id="chart-mask-left" class="absolute bg-neutral-10/50"></div>
              <div
                id="chart-mask-right"
                class="absolute bg-neutral-10/50"
              ></div>
            </div>
            <!-- Slider -->
            <div class="px-2 py-3">
              <Slider
                v-model="selectArea"
                :step="1"
                :min="0"
                :max="selectRange"
                range
                class="mx-2"
                @change="changeSelectArea($event)"
              />
            </div>
            <!-- Calendar / InputNumber group -->
            <div>
              <div
                v-if="selectedAttName.type === 'date'"
                class="flex justify-center items-center space-x-2 w-full"
              >
                <div>
                  <span class="block mb-2">Start time</span>
                  <DatePicker
                    v-model="startTime"
                    dateFormat="yy/mm/dd"
                    :panelProps="panelProps"
                    :minDate="startMinDate"
                    :maxDate="startMaxDate"
                    showTime
                    showIcon
                    hourFormat="24"
                    @date-select="sliderValueRange($event, 'start')"
                    id="startCalendar"
                  />
                </div>
                <span class="block mt-4">~</span>
                <div>
                  <span class="block mb-2">End time</span>
                  <DatePicker
                    v-model="endTime"
                    dateFormat="yy/mm/dd"
                    :panelProps="panelProps"
                    :minDate="endMinDate"
                    :maxDate="endMaxDate"
                    showTime
                    showIcon
                    hourFormat="24"
                    @date-select="sliderValueRange($event, 'end')"
                    id="endCalendar"
                  />
                </div>
              </div>
              <div
                v-else
                class="flex justify-center items-center space-x-2 w-full"
              >
                <InputNumber
                  v-model="valueStart"
                  :min="valueStartMin"
                  :max="valueStartMax"
                  :maxFractionDigits="2"
                  inputClass="w-24 text-sm text-right"
                  @blur="sliderValueRange($event, 'start')"
                ></InputNumber>
                <span class="block px-2">~</span>
                <InputNumber
                  v-model="valueEnd"
                  :min="valueEndMin"
                  :max="valueEndMax"
                  inputClass="w-24 text-sm text-right"
                  :maxFractionDigits="2"
                  @blur="sliderValueRange($event, 'end')"
                ></InputNumber>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </section>
</template>
<script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc.  All rights reserved.
// Authors:
//   chiayin.kuo@dsp.im (chiayin), 2023/1/31
//   cindy.chang@dsp.im (Cindy Chang), 2024/5/30
//   imacat.yang@dsp.im (imacat), 2023/9/23
/**
 * @module components/Discover/Map/Filter/Attributes
 *   Case attribute filter with dynamic form fields
 *   for filtering by attribute values.
 */

import { ref, computed, onMounted, onBeforeUnmount } from "vue";
import { storeToRefs } from "pinia";
import { useAllMapDataStore } from "@/stores/allMapData";
import { setLineChartData } from "@/module/setChartData.js";
import getMoment from "moment";
import InputNumber from "primevue/inputnumber";
import { Decimal } from "decimal.js";
import emitter from "@/utils/emitter";

const emit = defineEmits(["select-attribute"]);

const allMapDataStore = useAllMapDataStore();
const { filterAttrs } = storeToRefs(allMapDataStore);

const selectedAttName = ref({});
const selectedAttRange = ref(null);
const valueTypes = new Set(["int", "float", "date"]);
const classTypes = new Set(["boolean", "string"]);
const chartData = ref({});
const chartOptions = ref({});
const chartComplete = ref(null); // Rendered chart.js instance data
const selectArea = ref(null);
const selectRange = ref(1000); // Number of divisions for the selection range
const startTime = ref(null); // PrimeVue Calendar v-model
const endTime = ref(null); // PrimeVue Calendar v-model
const startMinDate = ref(null);
const startMaxDate = ref(null);
const endMinDate = ref(null);
const endMaxDate = ref(null);
const valueStart = ref(null); // PrimeVue InputNumber v-model
const valueEnd = ref(null); // PrimeVue InputNumber v-model
const valueStartMin = ref(null);
const valueStartMax = ref(null);
const valueEndMin = ref(null);
const valueEndMax = ref(null);
const tableClass =
  "w-full h-full !border-separate !border-spacing-x-2 !table-auto text-sm";
const headerModeClass =
  "w-8 !p-2 !bg-neutral-10 !border-neutral-500 sticky top-0 left-0 z-10 bg-neutral-10";
const headerClass =
  "!bg-neutral-10 !border-neutral-500 !py-2 sticky top-0 left-0 z-10 bg-neutral-10";
const bodyModeClass = "!p-2 !border-0";
const bodyClass = "break-words !py-2 !border-0";
const panelProps = {
  onClick: (event) => {
    event.stopPropagation();
  },
};
const tooltip = {
  attributeName: {
    value:
      "Attributes with too many discrete values are excluded from selection. But users can still view those attributes in the DATA page.",
    class: "!max-w-[212px] !text-[10px] !opacity-90",
  },
};

const attTotal = computed(() => {
  return filterAttrs.value.length;
});

const attRangeTotal = computed(() => {
  const type = selectedAttName.value.type;

  let result = null; // Initialize the result variable with null

  if (classTypes.has(type) && attRangeData.value) {
    result = `(${attRangeData.value.length})`; // Assign the length of attRangeData if it exists
  }
  return result;
});

const attRangeData = computed(() => {
  let data = [];
  const type = selectedAttName.value.type;
  const sum = selectedAttName.value.options
    .map((item) => item.freq)
    .reduce((acc, cur) => acc + cur, 0);
  data = selectedAttName.value.options.map((item, index) => {
    const ratio = item.freq / sum;
    const result = {
      id: index + 1,
      key: selectedAttName.value.key,
      type: type,
      value: item.value,
      occ_progress_bar: ratio * 100,
      occ_value: item.freq.toLocaleString("en-US"),
      occ_ratio: getPercentLabel(ratio),
      freq: item.freq,
    };
    result.label = null;
    if (type === "boolean") {
      result.label = item.value ? "Yes" : "No";
    } else {
      result.label = null;
    }
    return result;
  });
  return data.sort((x, y) => y.freq - x.freq);
});

// Get the selected Attribute radio's numeric-type data
const valueData = computed(() => {
  // filter returns an array, find returns the first matched element, so use find here.
  if (valueTypes.has(selectedAttName.value.type)) {
    const data = filterAttrs.value.find(
      (item) =>
        item.type === selectedAttName.value.type &&
        item.key === selectedAttName.value.key,
    );
    return data ?? null;
  }
  return null;
});

// Compute slider data; time format: millisecond timestamps
const sliderDataComputed = computed(() => {
  if (!valueData.value) return [];
  let xAxisMin;
  let xAxisMax;
  const min = valueData.value.min;
  const max = valueData.value.max;
  const type = valueData.value.type;
  switch (type) {
    case "dummy":
    case "date":
      xAxisMin = new Date(min).getTime();
      xAxisMax = new Date(max).getTime();
      break;
    default:
      xAxisMin = min;
      xAxisMax = max;
      break;
  }
  const range = xAxisMax - xAxisMin;
  const step = range / selectRange.value;
  let data = [];

  for (let i = 0; i <= selectRange.value; i++) {
    data.push(xAxisMin + step * i);
  }
  switch (type) {
    case "int":
      data = data.map((value) => {
        let result = Math.round(value);
        result = result === -0 ? 0 : result;
        return result;
      });
      break;
    case "float":
      data = data.map((value) => {
        let result = new Decimal(value.toFixed(2)).toNumber();
        result = result === -0 ? 0 : result;
        return result;
      });
      break;
    default:
      break;
  }
  return data;
});

// user select value type start and end
const attValueTypeStartEnd = computed(() => {
  let start;
  let end;
  const type = selectedAttName.value.type;

  switch (type) {
    case "dummy": //sonar-qube
    case "date":
      start = getMoment(startTime.value).format("YYYY-MM-DDTHH:mm:00");
      end = getMoment(endTime.value).format("YYYY-MM-DDTHH:mm:00");
      break;
    default:
      start = valueStart.value;
      end = valueEnd.value;
      break;
  }
  const data = {
    // Data to send to the backend
    type: type,
    data: {
      key: selectedAttName.value.key,
      min: start,
      max: end,
    },
  };
  emit("select-attribute", data);

  return [start, end];
});

const labelsData = computed(() => {
  if (!valueData.value) return [];
  const min = new Date(valueData.value.min).getTime();
  const max = new Date(valueData.value.max).getTime();
  const numPoints = 11;
  const step = (max - min) / (numPoints - 1);
  const data = [];
  for (let i = 0; i < numPoints; i++) {
    const x = min + i * step;
    data.push(x);
  }
  return data;
});

/**
 * Emits the current attribute selection when a row is selected or deselected.
 */
function onRowSelectionChange() {
  const type = selectedAttName.value.type;
  const data = {
    type: type,
    data: selectedAttRange.value,
  };
  emit("select-attribute", data);
}

/**
 * Selects all options in the categorical table.
 * @param {Event} e - The input event.
 */
function onRowSelectAll(e) {
  selectedAttRange.value = e.data;
  const type = selectedAttName.value.type;
  const data = {
    type: type,
    data: selectedAttRange.value,
  };
  emit("select-attribute", data);
}

/**
 * Deselects all options in the categorical table.
 */
function onRowUnelectAll() {
  selectedAttRange.value = null;
  const type = selectedAttName.value.type;
  const data = {
    type: type,
    data: selectedAttRange.value,
  };
  emit("select-attribute", data);
}

/**
 * Switches the attribute name radio selection.
 * @param {Event} e - The input event.
 */
function switchAttNameRadio(e) {
  selectedAttRange.value = null;
  startTime.value = null;
  endTime.value = null;
  valueStart.value = null;
  valueEnd.value = null;
  if (valueData.value) {
    // Switch Attribute Name
    // Initialize two-way bindings
    selectArea.value = [0, selectRange.value];
    const min = valueData.value.min;
    const max = valueData.value.max;
    switch (selectedAttName.value.type) {
      case "dummy": //sonar-qube
      case "date":
        // Clear two-way bindings except for date
        valueStart.value = null;
        valueEnd.value = null;
        // Initialize Calendar
        startMinDate.value = new Date(min);
        startMaxDate.value = new Date(max);
        endMinDate.value = new Date(min);
        endMaxDate.value = new Date(max);
        // Initialize: set the calendar range to match the timeline range
        startTime.value = new Date(min);
        endTime.value = new Date(max);
        break;
      default:
        // Clear date two-way bindings
        startTime.value = null;
        endTime.value = null;
        // Initialize InputNumber
        valueStartMin.value = min;
        valueStartMax.value = max;
        valueEndMin.value = min;
        valueEndMax.value = max;
        // Initialize: set the InputNumber range to match the timeline range
        valueStart.value = min;
        valueEnd.value = max;
        break;
    }
    // Send to backend
    // attValueTypeStartEnd.value; should this function be called? sonar-qube
    // Create chart
    createChart();
  }
}

/**
 * set progress bar width
 * @param   {number} value - The percentage value.
 * @returns {string} The CSS width style string.
 */
function progressWidth(value) {
  return `width:${value}%;`;
}

/**
 * Number to percentage
 * @param   {number} val - The raw ratio value.
 * @returns {string} The formatted percentage string.
 */
function getPercentLabel(val) {
  if (Number((val * 100).toFixed(1)) >= 100) return `100%`;
  else return `${(val * 100).toFixed(1)}%`;
}

/**
 * Adjusts the overlay mask size.
 * @param {object} chart - The Chart.js instance data.
 */
function resizeMask(chart) {
  if (selectRange.value === 0) return;
  const from = (selectArea.value[0] * 0.01) / (selectRange.value * 0.01);
  const to = (selectArea.value[1] * 0.01) / (selectRange.value * 0.01);
  resizeLeftMask(chart, from);
  resizeRightMask(chart, to);
}

/**
 * Adjusts the left overlay mask size.
 * @param {object} chart - The Chart.js instance data.
 */
function resizeLeftMask(chart, from) {
  const canvas = document.querySelector("#chartCanvasId canvas");
  const mask = document.getElementById("chart-mask-left");
  if (!canvas || !mask) return;
  mask.style.left = `${canvas.offsetLeft + chart.chartArea.left}px`;
  mask.style.width = `${chart.chartArea.width * from}px`;
  mask.style.top = `${canvas.offsetTop + chart.chartArea.top}px`;
  mask.style.height = `${chart.chartArea.height}px`;
}

/**
 * Adjusts the right overlay mask size.
 * @param {object} chart - The Chart.js instance data.
 */
function resizeRightMask(chart, to) {
  const canvas = document.querySelector("#chartCanvasId canvas");
  const mask = document.getElementById("chart-mask-right");
  if (!canvas || !mask) return;
  mask.style.left = `${canvas.offsetLeft + chart.chartArea.left + chart.chartArea.width * to}px`;
  mask.style.width = `${chart.chartArea.width * (1 - to)}px`;
  mask.style.top = `${canvas.offsetTop + chart.chartArea.top}px`;
  mask.style.height = `${chart.chartArea.height}px`;
}

/**
 * Creates and renders the Chart.js line chart for attribute data.
 */
function createChart() {
  const vData = valueData.value;
  const max = vData.chart.y_axis.max * 1.1;
  const data = setLineChartData(
    vData.chart.data,
    vData.chart.x_axis.max,
    vData.chart.x_axis.min,
  );
  const isDateType = vData.type === "date";
  const minX = vData.chart.x_axis.min;
  const maxX = vData.chart.x_axis.max;
  let setChartData = {};
  let setChartOptions = {};
  let setLabels = [];

  switch (vData.type) {
    case "int":
      setLabels = data.map((item) => Math.round(item.x));
      break;
    case "float":
      setLabels = data.map((item, index) => {
        let x;
        if (index === 0) {
          x = Math.floor(item.x * 100) / 100;
        } else if (index === data.length - 1) {
          item.x = Math.ceil(item.x * 100) / 100;
          x = item.x;
        } else {
          x = Math.round(item.x * 100) / 100;
        }
        return x;
      });
      break;
    case "date":
      setLabels = labelsData.value;
      break;
    default:
      break;
  }
  setChartData = {
    datasets: [
      {
        label: "Attribute Value",
        data: data,
        fill: "start",
        showLine: false,
        tension: 0.4,
        backgroundColor: "rgba(0,153,255)",
        pointRadius: 0,
      },
    ],
    labels: setLabels,
  };
  setChartOptions = {
    responsive: true,
    maintainAspectRatio: false,
    layout: {
      padding: {
        top: 16,
        left: 8,
        right: 8,
      },
    },
    plugins: {
      legend: false, // Hide legend
      filler: {
        propagate: false,
      },
      title: false,
    },
    animation: {
      onComplete: (e) => {
        chartComplete.value = e.chart;
        resizeMask(e.chart);
      },
    },
    interaction: {
      intersect: true,
    },
    scales: {
      y: {
        beginAtZero: true, // Scale includes 0
        max: max,
        ticks: {
          // Set tick intervals
          display: false, // Hide values, only show grid lines
          stepSize: max / 4,
        },
        grid: {
          color: "rgba(100,116,139)",
          z: 1,
        },
        border: {
          display: false, // Hide the extra border line on the left
        },
      },
    },
  };
  if (isDateType) {
    setChartOptions.scales.x = {
      type: "time",
      ticks: {
        min: minX,
        max: maxX,
        autoSkip: true, // Automatically determine whether to convert time units
        maxRotation: 0, // Do not rotate labels (0~50)
        color: "#334155",
        display: true,
        source: "labels", // Flexibly display label count proportionally
      },
      grid: {
        display: false, // Hide x-axis grid lines
      },
      time: {
        minUnit: "day", // Minimum display unit
        // displayFormats: {
        //   minute: 'HH:mm MMM d',
        //   hour: 'HH:mm MMM d',
        // }
      },
    };
  } else {
    setChartOptions.scales.x = {
      bounds: "data",
      type: "linear",
      min: minX,
      max: maxX,
      ticks: {
        autoSkip: true,
        maxRotation: 0, // Do not rotate labels (0~50)
        color: "#334155",
        callback: (value, index, values) => {
          let x;
          switch (vData.type) {
            case "int":
              return Math.round(value);
            case "float":
              switch (index) {
                case 0:
                  x = Math.floor(value * 100) / 100;
                  break;
                case values.length - 1:
                  x = Math.ceil(value * 100) / 100;
                  break;
                default:
                  x = Math.round(value * 100) / 100;
              }
              // Handle scientific notation and other format conversions
              // Decimal cannot handle numbers exceeding 16 digits
              x = new Intl.NumberFormat(undefined, {
                useGrouping: false,
              }).format(x);
              return x;
          }
        },
      },
      grid: {
        display: false, // Hide x-axis grid lines
      },
    };
  }
  chartData.value = setChartData;
  chartOptions.value = setChartOptions;
}

/**
 * Handles slider value changes.
 * @param {array} e [1, 100]
 */
function changeSelectArea(e) {
  // When the calendar changes, the slider follows
  const sliderData = sliderDataComputed.value;
  const start = sliderData[e[0].toFixed()];
  const end = sliderData[e[1].toFixed()]; // Get the index, which must be an integer.

  switch (selectedAttName.value.type) {
    case "dummy":
    case "date":
      startTime.value = new Date(start);
      endTime.value = new Date(end);
      // Reset the start/end calendar selection range
      endMinDate.value = new Date(start);
      startMaxDate.value = new Date(end);
      break;
    default:
      valueStart.value = start;
      valueEnd.value = end;
      // Reset the start/end selection range
      valueEndMin.value = start;
      valueStartMax.value = end;
      break;
  }
  // Recalculate the chart mask
  resizeMask(chartComplete.value);
  // Execute timeFrameStartEnd to update the data
  // attValueTypeStartEnd.value; should this function be called? sonar-qube
}

/**
 * Updates the slider and chart when a start or end time is selected.
 * @param {object} e - The date object or blur event.
 * @param {string} direction start or end
 */
function sliderValueRange(e, direction) {
  // Find the closest index; time format: millisecond timestamps
  const sliderData = sliderDataComputed.value;
  const isDateType = selectedAttName.value.type === "date";
  let targetTime = [];
  let inputValue;

  if (isDateType)
    targetTime = [
      new Date(attValueTypeStartEnd.value[0]).getTime(),
      new Date(attValueTypeStartEnd.value[1]).getTime(),
    ];
  else
    targetTime = [attValueTypeStartEnd.value[0], attValueTypeStartEnd.value[1]];

  const closestIndexes = targetTime.map((target) => {
    let closestIndex = 0;
    closestIndex =
      ((target - sliderData[0]) /
        (sliderData[sliderData.length - 1] - sliderData[0])) *
      sliderData.length;
    let result = Math.round(Math.abs(closestIndex));
    result = Math.min(result, selectRange.value);
    return result;
  });
  // Update the slider
  selectArea.value = closestIndexes;
  // Reset the start/end calendar selection range
  if (!isDateType) inputValue = Number(e.value.replaceAll(",", ""));
  if (direction === "start") {
    if (isDateType) {
      endMinDate.value = e;
    } else {
      valueEndMin.value = inputValue;
    }
  } else if (direction === "end") {
    if (isDateType) {
      startMaxDate.value = e;
    } else {
      valueStartMax.value = inputValue;
    }
  }
  // Recalculate the chart mask
  if (!Number.isNaN(closestIndexes[0]) && !Number.isNaN(closestIndexes[1]))
    resizeMask(chartComplete.value);
  else return;
}

// created() equivalent
emitter.on("map-filter-reset", (value) => {
  if (value) {
    selectedAttRange.value = null;
    if (valueData.value && valueTypes.has(selectedAttName.value.type)) {
      const min = valueData.value.min;
      const max = valueData.value.max;
      startTime.value = new Date(min);
      endTime.value = new Date(max);
      valueStart.value = min;
      valueEnd.value = max;
      selectArea.value = [0, selectRange.value];
      resizeMask(chartComplete.value);
    }
  }
});

onMounted(() => {
  // Slider
  selectArea.value = [0, selectRange.value]; // Initialize the slider
});

onBeforeUnmount(() => {
  selectedAttName.value = {};
  emitter.off("map-filter-reset");
});
</script>
<style scoped>
@reference "../../../../assets/tailwind.css";
:deep(table tbody td:nth-child(2)) {
  @apply whitespace-nowrap break-keep overflow-hidden text-ellipsis max-w-0;
}
</style>
