<template>
  <main class="h-screen-main relative">
    <div class="h-full relative bg-neutral-50">
      <div class="flex justify-start items-start p-4 h-full">
        <!-- tag -->
        <aside
          class="border-r border-neutral-300 pr-4 mr-4 h-full sticky top-0 self-start"
        >
          <section class="px-2 space-y-2 w-56 h-full">
            <div>
              <p class="h1">{{ i18next.t("Compare.timeUsage") }}</p>
              <ul class="list-disc list-inside text-sm leading-5 pl-3">
                <li
                  v-for="(item, index) in timeUsageData"
                  :key="index"
                  :class="{ active: isActive === item.tagId }"
                  @click="handleClick(item.tagId)"
                  class="cursor-pointer hover:text-primary"
                >
                  {{ item.label }}
                </li>
              </ul>
            </div>
            <div>
              <p class="h1">{{ i18next.t("Compare.frequency") }}</p>
              <ul class="list-disc list-inside text-sm leading-5 pl-3">
                <li
                  v-for="(item, index) in frequencyData"
                  :key="index"
                  :class="{ active: isActive === item.tagId }"
                  @click="handleClick(item.tagId)"
                  class="cursor-pointer hover:text-primary"
                >
                  {{ item.label }}
                </li>
              </ul>
            </div>
          </section>
        </aside>
        <!-- graph -->
        <article
          class="w-full h-full pr-2 mr-2 overflow-x-hidden overflow-y-auto scrollbar scroll-smooth"
        >
          <section>
            <p class="h1 px-4 border-b border-neutral-900">
              <span class="material-symbols-outlined mr-2 align-middle">
                {{ i18next.t("Compare.schedule") }}
              </span>
              {{ i18next.t("Compare.timeUsage") }}
            </p>
            <ul class="list-disc list-inside px-4 pl-7 text-sm">
              <li id="cycleTime" class="scroll-smooth">
                <span class="inline-block py-4">{{
                  i18next.t("Compare.cycleEfficiency")
                }}</span>
                <ul>
                  <li
                    class="bg-neutral-10 mb-4 p-1 border border-neutral-300 rounded"
                  >
                    <span
                      class="block font-bold text-sm leading-loose text-center my-2"
                    >
                      {{ contentData.avgCycleTime.title }}
                    </span>
                    <Chart
                      type="line"
                      :data="avgCycleTimeData"
                      :options="avgCycleTimeOptions"
                      class="h-96"
                    />
                  </li>
                  <li
                    class="bg-neutral-10 p-1 border border-neutral-300 rounded"
                  >
                    <span
                      class="block font-bold text-sm leading-loose text-center my-2"
                    >
                      {{ contentData.avgCycleEfficiency.title }}
                      <span
                        class="material-symbols-outlined align-middle ml-2 cursor-pointer !text-base"
                        v-tooltip.bottom="tooltip.avgCycleEfficiency"
                      >
                        {{ i18next.t("Compare.info") }}
                      </span>
                    </span>
                    <Chart
                      type="bar"
                      :data="avgCycleEfficiencyData"
                      :options="avgCycleEfficiencyOptions"
                      class="h-96"
                    />
                  </li>
                </ul>
              </li>
              <li id="processingTime">
                <span class="inline-block py-4 text-sm">{{
                  i18next.t("Compare.ProcessingTime")
                }}</span>
                <ul>
                  <li
                    class="bg-neutral-10 mb-4 p-1 border border-neutral-300 rounded"
                  >
                    <span
                      class="block font-bold text-sm leading-loose text-center my-2"
                    >
                      {{ contentData.avgProcessTime.title }}
                    </span>
                    <Chart
                      type="line"
                      :data="avgProcessTimeData"
                      :options="avgProcessTimeOptions"
                      class="h-96"
                    />
                  </li>
                  <li
                    class="bg-neutral-10 p-1 border border-neutral-300 rounded"
                  >
                    <span
                      class="block font-bold text-sm leading-loose text-center my-2"
                    >
                      {{ contentData.avgProcessTimeByTask.title }}
                    </span>
                    <Chart
                      type="bar"
                      :data="avgProcessTimeByTaskData"
                      :options="avgProcessTimeByTaskOptions"
                      class="h-[500px]"
                      :style="{ height: avgProcessTimeByTaskHeight }"
                    />
                  </li>
                </ul>
              </li>
              <li id="waitingTime">
                <span class="inline-block py-4 text-sm">{{
                  i18next.t("Compare.WaitingTime")
                }}</span>
                <ul>
                  <li
                    class="bg-neutral-10 mb-4 p-1 border border-neutral-300 rounded"
                  >
                    <span
                      class="block font-bold text-sm leading-loose text-center my-2"
                    >
                      {{ contentData.avgWaitingTime.title }}
                      <span
                        class="material-symbols-outlined align-middle ml-2 cursor-pointer !text-base"
                        v-tooltip.bottom="tooltip.avgWaitingTime"
                      >
                        info
                      </span></span
                    >
                    <Chart
                      type="line"
                      :data="avgWaitingTimeData"
                      :options="avgWaitingTimeOptions"
                      class="h-96"
                    />
                  </li>
                  <li
                    class="bg-neutral-10 p-1 border border-neutral-300 rounded"
                  >
                    <span
                      class="block font-bold text-sm leading-loose text-center my-2"
                    >
                      {{ contentData.avgWaitingTimeByEdge.title }}
                      <span
                        class="material-symbols-outlined align-middle ml-2 cursor-pointer !text-base"
                        v-tooltip.bottom="tooltip.avgWaitingTimeByEdge"
                        >{{ i18next.t("Compare.info") }}</span
                      ></span
                    >
                    <div>
                      <Chart
                        v-if="avgWaitingTimeByEdgeData !== null"
                        type="bar"
                        :data="avgWaitingTimeByEdgeData"
                        :options="avgWaitingTimeByEdgeOptions"
                        :style="{ height: avgWaitingTimeByEdgeHeight }"
                        class="h-[500px]"
                      />
                      <div v-else class="h-96 bg-neutral-100 m-4 flex">
                        <p class="h2 text-danger m-auto">
                          {{ i18next.t("Compare.NoWaitingTime") }}
                        </p>
                      </div>
                    </div>
                  </li>
                </ul>
              </li>
            </ul>
          </section>
          <section>
            <p class="h1 px-4 border-b border-neutral-900 mt-2">
              <span class="material-symbols-outlined mr-2 align-middle">
                {{ i18next.t("Compare.moving") }}
              </span>
              {{ i18next.t("Compare.frequency") }}
            </p>
            <ul class="list-disc list-inside px-4 pl-7 text-sm">
              <li id="cases">
                <span class="inline-block py-4">{{
                  i18next.t("Compare.NumberOfCases")
                }}</span>
                <ul>
                  <li
                    class="bg-neutral-10 mb-4 p-1 border border-neutral-300 rounded"
                  >
                    <span
                      class="block font-bold text-sm leading-loose text-center my-2"
                      >{{ contentData.freq.title }}</span
                    >
                    <FreqChart
                      v-if="compareDashboardData"
                      :chartData="compareDashboardData?.freq?.cases"
                      :content="contentData?.freq"
                      yUnit="count"
                      pageName="Compare"
                    />
                  </li>
                  <li
                    class="bg-neutral-10 p-1 border border-neutral-300 rounded"
                  >
                    <span
                      class="block font-bold text-sm leading-loose text-center my-2"
                    >
                      {{ contentData.casesByTask.title }}
                    </span>
                    <Chart
                      type="bar"
                      :data="casesByTaskData"
                      :options="casesByTaskOptions"
                      :style="{ height: casesByTaskHeight }"
                      class="h-[500px]"
                    />
                  </li>
                </ul>
              </li>
            </ul>
          </section>
        </article>
        <!-- Sidebar: State -->
        <div class="bg-transparent z-10">
          <ul class="flex flex-col justify-center items-center">
            <li
              class="inline-flex items-center justify-center border border-neutral-500 rounded-full w-9 h-9 cursor-pointer bg-neutral-50 drop-shadow hover:border-primary"
              @click="sidebarState = !sidebarState"
              :class="{ 'border-primary': sidebarState }"
              id="compareState"
            >
              <span
                class="material-symbols-outlined !text-2xl text-neutral-500 hover:text-primary p-1.5"
                :class="[sidebarState ? 'text-primary' : 'text-neutral-500']"
              >
                info
              </span>
            </li>
          </ul>
        </div>
        <SidebarStates v-model:visible="sidebarState"></SidebarStates>
      </div>
    </div>
  </main>
</template>
<script setup>
// The Lucia project.
// Copyright 2024-2026 DSP, inc.  All rights reserved.
// Authors:
//   cindy.chang@dsp.im (Cindy Chang), 2024/5/30
/**
 * @module views/Compare/Dashboard/Compare
 *   Performance comparison dashboard with side-by-side
 *   charts comparing two datasets.
 */

import { ref, onMounted } from "vue";
import { useRoute } from "vue-router";
import { storeToRefs } from "pinia";
import moment from "moment";
import { useLoadingStore } from "@/stores/loading";
import { useCompareStore } from "@/stores/compare";
import SidebarStates from "@/components/Compare/SidebarStates.vue";
import { setLineChartData } from "@/module/setChartData.js";
import {
  simpleTimeLabel,
  followTimeLabel,
  setTimeStringFormatBaseOnTimeDifference,
  mapTimestampToAxisTicksByFormat,
  getStepSizeOfYTicks,
  getYTicksByIndex,
} from "@/module/timeLabel.js";
import i18next from "@/i18n/i18n";
import {
  knownLayoutChartOption,
  knownScaleLineChartOptions,
  knownScaleHorizontalChartOptions,
  knownScaleBarChartOptions,
  GRID_COLOR,
} from "@/constants/constants.js";
import FreqChart from "../../Discover/Performance/FreqChart.vue";

const route = useRoute();

// Stores
const loadingStore = useLoadingStore();
const compareStore = useCompareStore();
const { isLoading } = storeToRefs(loadingStore);
const { compareDashboardData } = storeToRefs(compareStore);

// Data
const timeUsageData = [
  { tagId: "#cycleTime", label: i18next.t("Compare.cycleEfficiency") },
  { tagId: "#processingTime", label: i18next.t("Compare.ProcessingTime") },
  { tagId: "#waitingTime", label: i18next.t("Compare.WaitingTime") },
];
const frequencyData = [
  { tagId: "#cases", label: i18next.t("Compare.NumberOfCases") },
];
const contentData = {
  avgCycleTime: {
    title: i18next.t("Compare.avgCycleTimeTitle"),
    x: i18next.t("Compare.labelDateX"),
    y: i18next.t("Compare.avgCycleTimeY"),
  },
  avgCycleEfficiency: {
    title: i18next.t("Compare.avgCycleEfficiencyTitle"),
    x: i18next.t("Compare.labelDateX"),
    y: i18next.t("Compare.avgCycleEfficiencyY"),
  },
  avgProcessTime: {
    title: i18next.t("Compare.avgProcessTimeTitle"),
    x: i18next.t("Compare.labelDateX"),
    y: i18next.t("Compare.avgProcessTimeY"),
  },
  avgProcessTimeByTask: {
    title: i18next.t("Compare.avgProcessTimeByTaskTitle"),
    x: i18next.t("Compare.avgProcessTimeByTaskX"),
    y: i18next.t("Compare.labelActivityY"),
  },
  avgWaitingTime: {
    title: i18next.t("Compare.avgWaitingTimeTitle"),
    x: i18next.t("Compare.labelDateX"),
    y: i18next.t("Compare.avgWaitingTimeY"),
  },
  avgWaitingTimeByEdge: {
    title: i18next.t("Compare.avgWaitingTimeByEdgeTitle"),
    x: i18next.t("Compare.avgWaitingTimeByEdgeX"),
    y: i18next.t("Compare.avgWaitingTimeByEdgeY"),
  },
  freq: {
    title: i18next.t("Compare.freqTitle"),
    x: i18next.t("Compare.labelDateX"),
    y: i18next.t("Compare.freqY"),
  },
  casesByTask: {
    title: i18next.t("Compare.casesByTaskTitle"),
    x: i18next.t("Compare.casesByTaskX"),
    y: i18next.t("Compare.labelActivityY"),
  },
};
const tooltip = {
  avgCycleEfficiency: {
    value: i18next.t("Compare.avgCycleEfficiency"),
    class: "!max-w-[212px] !text-[10px] !opacity-80",
    autoHide: false,
  },
  avgWaitingTime: {
    value: i18next.t("Compare.avgWaitingTime"),
    class: "!max-w-[212px] !text-[10px] !opacity-80",
    autoHide: false,
  },
  avgWaitingTimeByEdge: {
    value: i18next.t("Compare.avgWaitingTimeByEdge"),
    class: "!max-w-[212px] !text-[10px] !opacity-80",
    autoHide: false,
  },
};

const isActive = ref(null);
const avgCycleTimeData = ref(null);
const avgCycleTimeOptions = ref(null);
const avgCycleEfficiencyData = ref(null);
const avgCycleEfficiencyOptions = ref(null);
const avgProcessTimeData = ref(null);
const avgProcessTimeOptions = ref(null);
const avgProcessTimeByTaskData = ref(null);
const avgProcessTimeByTaskOptions = ref(null);
const avgWaitingTimeData = ref(null);
const avgWaitingTimeOptions = ref(null);
const avgWaitingTimeByEdgeData = ref(null);
const avgWaitingTimeByEdgeOptions = ref(null);
const freqData = ref(null);
const freqOptions = ref(null);
const casesByTaskData = ref(null);
const casesByTaskOptions = ref(null);
const horizontalBarHeight = 500;
const avgProcessTimeByTaskHeight = ref(500);
const avgWaitingTimeByEdgeHeight = ref(500);
const casesByTaskHeight = ref(500);
const colorPrimary = "#0099FF";
const colorSecondary = "#FFAA44";
const sidebarState = ref(false);

// Methods
/**
 * Scrolls to the selected chart section.
 * @param {string} tagId - The anchor tag ID to navigate to.
 */
function handleClick(tagId) {
  isActive.value = tagId;

  if (isSafeTagId(tagId)) {
    globalThis.location.href = tagId;
  } else {
    console.warn("Unsafe tagId: ", tagId);
  }
}

/**
 * Validates that a tag ID is safe for navigation.
 * @param {string} tagId - The tag ID to validate.
 * @returns {boolean} True if the tag ID is safe.
 */
function isSafeTagId(tagId) {
  const pattern = /^#?[a-zA-Z0-9-]*$/;
  return pattern.test(tagId);
}

/**
 * Generates evenly-spaced X-axis label timestamps.
 * @param {object} valueData - Object with min and max date strings.
 * @returns {Array<number>} Array of timestamp values.
 */
function setXLabelsData(valueData) {
  const min = new Date(valueData.min).getTime();
  const max = new Date(valueData.max).getTime();
  const numPoints = 12;
  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;
}

/**
 * Calculates the height for a horizontal bar chart based on bar count.
 * @param {object} chartData - The chart data with x_axis labels.
 * @returns {string} The CSS height string.
 */
function getHorizontalBarHeight(chartData) {
  const totalBars = chartData.x_axis.labels.length;
  let hBarHeight = horizontalBarHeight;

  if (totalBars > 10) {
    hBarHeight = (totalBars - 10) * 16 * 2 + horizontalBarHeight;
  }

  return hBarHeight + "px";
}

/**
 * Builds a line chart configuration for Chart.js.
 * @param {object} chartData - The chart data from the API.
 * @param {object} content - The axis label content.
 * @param {string} yUnit - 'date' or 'count'.
 * @returns {Array} [chartData, chartOptions] tuple.
 */
function getLineChart(chartData, content, yUnit) {
  if (!chartData?.data || chartData.data.length < 2) return [];
  let datasetsPrimary;
  let datasetsSecondary;
  const minX = chartData.x_axis.min;
  const maxX = chartData.x_axis.max;
  let xLabelData;
  const labelPrimary = chartData.data[0].label;
  const labelSecondary = chartData.data[1].label;
  let primeVueSetData = {};
  let primeVueSetOption = {};
  const getMoment = (time) => {
    return moment(time).format("YYYY/M/D HH:mm:ss");
  };
  const getSimpleTimeLabel = simpleTimeLabel;

  switch (yUnit) {
    case "date":
      datasetsPrimary = setLineChartData(
        chartData.data[0].data,
        chartData.x_axis.max,
        chartData.x_axis.min,
        false,
        chartData.y_axis.max,
        chartData.y_axis.min,
      );
      datasetsSecondary = setLineChartData(
        chartData.data[1].data,
        chartData.x_axis.max,
        chartData.x_axis.min,
        false,
        chartData.y_axis.max,
        chartData.y_axis.min,
      );
      xLabelData = setXLabelsData(chartData.x_axis);
      break;
    case "count":
      datasetsPrimary = chartData.data[0].data;
      datasetsSecondary = chartData.data[1].data;
      xLabelData = chartData.data[0].data.map((item) =>
        new Date(item.x).getTime(),
      );
      break;
  }

  const formatToSet = setTimeStringFormatBaseOnTimeDifference(minX, maxX);
  const ticksOfXAxis = mapTimestampToAxisTicksByFormat(xLabelData, formatToSet);
  const customizedScaleOption = getCustomizedScaleOption(
    knownScaleLineChartOptions,
    {
      customizeOptions: {
        content,
        ticksOfXAxis,
      },
    },
  );
  primeVueSetData = {
    labels: xLabelData,
    datasets: [
      {
        label: labelPrimary,
        data: datasetsPrimary,
        fill: false,
        tension: 0,
        borderColor: colorPrimary,
        pointBackgroundColor: colorPrimary,
      },
      {
        label: labelSecondary,
        data: datasetsSecondary,
        fill: false,
        tension: 0,
        borderColor: colorSecondary,
        pointBackgroundColor: colorSecondary,
      },
    ],
  };
  primeVueSetOption = {
    responsive: true,
    maintainAspectRatio: false,
    layout: {
      padding: {
        top: 16,
        left: 8,
        right: 8,
      },
    },
    plugins: {
      legend: false,
      tooltip: {
        mode: "index",
        titleFont: { weight: "normal" },
        callbacks: {
          title: function (context) {
            return `${content.x}: ${getMoment(context[0].parsed.x)}`;
          },
        },
      },
      title: {
        display: false,
      },
    },
    scales: customizedScaleOption,
  };
  switch (yUnit) {
    case "date":
      primeVueSetOption.plugins.tooltip.callbacks.label = function (context) {
        const value = getSimpleTimeLabel(context.parsed.y, 2);

        switch (context.datasetIndex) {
          case 0:
            return `${labelPrimary}: ${value}`;
          case 1:
            return `${labelSecondary}: ${value}`;
        }
      };
      primeVueSetOption.scales.x.min = minX;
      primeVueSetOption.scales.x.max = maxX;
      primeVueSetOption.scales.y.ticks.callback = function (
        value,
        index,
        ticks,
      ) {
        const { resultStepSize: YTickStepSize, unitToUse } =
          getStepSizeOfYTicks(ticks[ticks.length - 1].value, ticks.length);
        return getYTicksByIndex(YTickStepSize, index, unitToUse);
      };
      break;
    case "count":
      primeVueSetOption.scales.y.ticks.precision = 0;
      primeVueSetOption.plugins.tooltip.callbacks.label = function (context) {
        const value = context.parsed.y;

        switch (context.datasetIndex) {
          case 0:
            return `${labelPrimary}: ${value}`;
          case 1:
            return `${labelSecondary}: ${value}`;
        }
      };
      break;
  }

  return [primeVueSetData, primeVueSetOption];
}

/**
 * Builds a bar chart configuration for Chart.js.
 * @param {object} chartData - The chart data from the API.
 * @param {object} content - The axis label content.
 * @param {string} caller - Identifier for chart-specific options.
 * @returns {Array} [chartData, chartOptions] tuple.
 */
function getBarChart(chartData, content, caller) {
  if (!chartData?.data || chartData.data.length < 2) return [];
  const getMoment = (time) => moment(time).format("YYYY/MM/DD");
  const labelPrimary = chartData.data[0].label;
  const labelSecondary = chartData.data[1].label;
  let primeVueSetData = {};
  let primeVueSetOption = {};

  const datasetsPrimary = chartData.data[0].data.map((value) => {
    return {
      x: getMoment(value.x),
      y: value.y === null ? null : value.y * 100,
    };
  });
  const xDataPrimary = datasetsPrimary.map((i) => i.x);
  const yDataPrimary = datasetsPrimary.map((i) => i.y);
  const datasetsSecondary = chartData.data[1].data.map((value) => {
    return {
      x: getMoment(value.x),
      y: value.y === null ? null : value.y * 100,
    };
  });
  const yDataSecondary = datasetsSecondary.map((i) => i.y);

  primeVueSetData = {
    labels: xDataPrimary,
    datasets: [
      {
        label: labelPrimary,
        data: yDataPrimary,
        backgroundColor: colorPrimary,
      },
      {
        label: labelSecondary,
        data: yDataSecondary,
        backgroundColor: colorSecondary,
      },
    ],
  };
  primeVueSetOption = {
    responsive: true,
    maintainAspectRatio: false,
    layout: knownLayoutChartOption,
    interaction: {
      intersect: false,
      mode: "index",
    },
    plugins: {
      legend: false,
      tooltip: {
        titleFont: { weight: "normal" },
        callbacks: {
          title: function (context) {
            return `${content.x}: ${context[0].label}`;
          },
          label: function (context) {
            const value = `${(context.parsed.y * 10).toFixed(2)}%`;
            switch (context.datasetIndex) {
              case 0:
                return `${labelPrimary}: ${value}`;
              case 1:
                return `${labelSecondary}: ${value}`;
            }
          },
        },
      },
      title: {
        display: false,
      },
    },
    scales: customizeScaleChartOptionTitleByContent(
      knownScaleBarChartOptions,
      content,
    ),
  };

  primeVueSetOption.scales = {
    ...primeVueSetOption.scales,
    x: {
      ticks: {
        callback: function (value, index, ticks) {
          return moment(xDataPrimary[index]).format("YYYY/MM");
        },
      },
    },
  };

  if (caller === "Cycle Eff") {
    primeVueSetOption.scales.y.reverse = true;
    primeVueSetOption.scales.y.ticks.callback = function (value, index, ticks) {
      return 10 * index;
    };
    primeVueSetOption.scales.y.grid = {
      color: GRID_COLOR,
    };
    primeVueSetOption.scales.x.grid = {
      display: false,
    };
  }

  return [primeVueSetData, primeVueSetOption];
}

/**
 * Builds a horizontal bar chart configuration for Chart.js.
 * @param {object} chartData - The chart data from the API.
 * @param {object} content - The axis label content.
 * @param {boolean} isSingle - Whether labels are single values.
 * @param {string} xUnit - 'date' or 'count'.
 * @returns {Array} [chartData, chartOptions] tuple.
 */
function getHorizontalBarChart(chartData, content, isSingle, xUnit) {
  const maxY = chartData.y_axis.max;
  const getSimpleTimeLabel = simpleTimeLabel;
  const getFollowTimeLabel = followTimeLabel;
  const labelPrimary = chartData.data[0].label;
  const labelSecondary = chartData.data[1].label;
  let primeVueSetData = {};
  let primeVueSetOption = {};

  const datasetsPrimary = chartData.data[0].data;
  const datasetsSecondary = chartData.data[1].data;
  datasetsPrimary.sort((a, b) => b.y - a.y);
  datasetsSecondary.sort((a, b) => {
    const indexA = datasetsPrimary.findIndex((item) => item.x === a.x);
    const indexB = datasetsPrimary.findIndex((item) => item.x === b.x);
    return indexA - indexB;
  });

  const xLabelData = datasetsPrimary.map((item) => item.x);
  const yDataPrimary = datasetsPrimary.map((item) => item.y);
  const yDataSecondary = datasetsSecondary.map((item) => item.y);

  primeVueSetData = {
    labels: xLabelData,
    datasets: [
      {
        label: labelPrimary,
        data: yDataPrimary,
        backgroundColor: colorPrimary,
      },
      {
        label: labelSecondary,
        data: yDataSecondary,
        backgroundColor: colorSecondary,
      },
    ],
  };
  primeVueSetOption = {
    indexAxis: "y",
    responsive: true,
    maintainAspectRatio: false,
    layout: {
      padding: {
        top: 16,
        left: 8,
        right: 8,
      },
    },
    plugins: {
      legend: false,
      tooltip: {
        mode: "index",
        titleFont: { weight: "normal" },
        callbacks: {},
      },
      title: {
        display: false,
      },
    },
    scales: customizeScaleChartOptionTitleByContent(
      knownScaleHorizontalChartOptions,
      null,
    ),
  };
  switch (xUnit) {
    case "date":
      primeVueSetOption.plugins.tooltip.callbacks.label = function (context) {
        const value =
          context.parsed.x === null
            ? "n/a"
            : getSimpleTimeLabel(context.parsed.x, 2);
        switch (context.datasetIndex) {
          case 0:
            return `${labelPrimary}: ${value}`;
          case 1:
            return `${labelSecondary}: ${value}`;
        }
      };
      primeVueSetOption.scales.x.ticks.callback = function (
        value,
        index,
        ticks,
      ) {
        return getFollowTimeLabel(value, maxY, 1);
      };
      break;
    case "count":
    default:
      primeVueSetOption.scales.x.ticks.precision = 0;
      primeVueSetOption.plugins.tooltip.callbacks.label = function (context) {
        const value = context.parsed.x === null ? "n/a" : context.parsed.x;
        switch (context.datasetIndex) {
          case 0:
            return `${labelPrimary}: ${value}`;
          case 1:
            return `${labelSecondary}: ${value}`;
        }
      };
      break;
  }
  if (isSingle) {
    primeVueSetOption.plugins.tooltip.callbacks.title = function (context) {
      return `${content.y}: ${context[0].label}`;
    };
    primeVueSetOption.scales.y.ticks.callback = function (value, index, ticks) {
      const label = xLabelData[index];
      if (label) {
        return label.length > 21 ? `${label.substring(0, 18)}...` : label;
      }
    };
  } else {
    primeVueSetOption.plugins.tooltip.callbacks.title = function (context) {
      return `${content.y}: ${context[0].label.replace(",", " - ")}`;
    };
    primeVueSetOption.scales.y.ticks.callback = function (value, index, ticks) {
      const label = xLabelData[index];
      let labelStart = label[0];
      let labelEnd = label[1];

      labelStart =
        labelStart.length > 10
          ? `${labelStart.substring(0, 7)}...`
          : labelStart;
      labelEnd =
        labelEnd.length > 10 ? `${labelEnd.substring(0, 7)}...` : labelEnd;
      return labelStart + " - " + labelEnd;
    };
  }

  return [primeVueSetData, primeVueSetOption];
}

/**
 * Customizes Chart.js scale options with content and tick data.
 * @param {object} whichScaleObj - The base scale options object.
 * @param {object} options - Options containing content and ticksOfXAxis.
 * @returns {object} The customized scale options.
 */
function getCustomizedScaleOption(
  whichScaleObj,
  { customizeOptions: { content, ticksOfXAxis } },
) {
  let resultScaleObj;
  resultScaleObj = customizeScaleChartOptionTitleByContent(
    whichScaleObj,
    content,
  );
  resultScaleObj = customizeScaleChartOptionTicks(resultScaleObj, ticksOfXAxis);
  return resultScaleObj;
}

/**
 * Sets axis titles on a scale options object.
 * @param {object} whichScaleObj - The base scale options.
 * @param {object} content - Object with x and y axis title text.
 * @returns {object} The scale options with updated titles.
 */
function customizeScaleChartOptionTitleByContent(whichScaleObj, content) {
  if (!content) {
    return whichScaleObj;
  }

  return {
    ...whichScaleObj,
    x: {
      ...whichScaleObj.x,
      title: {
        ...whichScaleObj.x.title,
        text: content.x,
      },
    },
    y: {
      ...whichScaleObj.y,
      title: {
        ...whichScaleObj.y.title,
        text: content.y,
      },
    },
  };
}

/**
 * Sets custom tick callbacks on a scale options object.
 * @param {object} scaleObjectToAlter - The scale options to modify.
 * @param {Array} ticksOfXAxis - The formatted tick labels.
 * @returns {object} The scale options with custom ticks.
 */
function customizeScaleChartOptionTicks(scaleObjectToAlter, ticksOfXAxis) {
  return {
    ...scaleObjectToAlter,
    x: {
      ...scaleObjectToAlter.x,
      ticks: {
        ...scaleObjectToAlter.x.ticks,
        callback: function (value, index) {
          return ticksOfXAxis[index];
        },
      },
    },
  };
}

/**
 * Builds an alternative line chart configuration with inline scales.
 * @param {object} chartData - The chart data from the API.
 * @param {object} content - The axis label content.
 * @param {string} yUnit - 'date' or 'count'.
 * @returns {Array} [chartData, chartOptions] tuple.
 */
function getLineChart0(chartData, content, yUnit) {
  if (!chartData?.data || chartData.data.length < 2) return [];
  let datasetsPrimary;
  let datasetsSecondary;
  const minX = chartData.x_axis.min;
  const maxX = chartData.x_axis.max;
  let xLabelData;
  const labelPrimary = chartData.data[0].label;
  const labelSecondary = chartData.data[1].label;
  let primeVueSetData = {};
  let primeVueSetOption = {};
  const getMoment = (time) => {
    return moment(time).format("YYYY/M/D HH:mm:ss");
  };
  const getSimpleTimeLabel = simpleTimeLabel;

  switch (yUnit) {
    case "date":
      datasetsPrimary = setLineChartData(
        chartData.data[0].data,
        chartData.x_axis.max,
        chartData.x_axis.min,
        false,
        chartData.y_axis.max,
        chartData.y_axis.min,
      );
      datasetsSecondary = setLineChartData(
        chartData.data[1].data,
        chartData.x_axis.max,
        chartData.x_axis.min,
        false,
        chartData.y_axis.max,
        chartData.y_axis.min,
      );
      xLabelData = setXLabelsData(chartData.x_axis);
      break;
    case "count":
      datasetsPrimary = chartData.data[0].data;
      datasetsSecondary = chartData.data[1].data;
      xLabelData = chartData.data[0].data.map((item) =>
        new Date(item.x).getTime(),
      );
      break;
  }

  const formatToSet = setTimeStringFormatBaseOnTimeDifference(minX, maxX);
  const ticksOfXAxis = mapTimestampToAxisTicksByFormat(xLabelData, formatToSet);

  primeVueSetData = {
    labels: xLabelData,
    datasets: [
      {
        label: labelPrimary,
        data: datasetsPrimary,
        fill: false,
        tension: 0,
        borderColor: colorPrimary,
        pointBackgroundColor: colorPrimary,
      },
      {
        label: labelSecondary,
        data: datasetsSecondary,
        fill: false,
        tension: 0,
        borderColor: colorSecondary,
        pointBackgroundColor: colorSecondary,
      },
    ],
  };
  primeVueSetOption = {
    responsive: true,
    maintainAspectRatio: false,
    layout: {
      padding: {
        top: 16,
        left: 8,
        right: 8,
      },
    },
    plugins: {
      legend: false,
      tooltip: {
        mode: "index",
        titleFont: { weight: "normal" },
        callbacks: {
          title: function (context) {
            return `${content.x}: ${getMoment(context[0].parsed.x)}`;
          },
          label: function (context) {
            return `${content.y}: ${getSimpleTimeLabel(context.parsed.y, 2)}`;
          },
        },
      },
      title: {
        display: false,
      },
    },
    scales: {
      x: {
        min: minX,
        max: maxX,
        type: "time",
        title: {
          display: true,
          color: "#334155",
          font: {
            size: 12,
            lineHeight: 2,
          },
          text: content.x,
        },
        time: {
          displayFormats: {
            second: "h:mm:ss",
            minute: "M/d h:mm",
            hour: "M/d h:mm",
            day: "M/d h",
            month: "y/M/d",
          },
          round: true,
        },
        ticks: {
          padding: 8,
          display: true,
          maxRotation: 0,
          color: "#64748b",
          source: "labels",
          callback: function (value, index) {
            return ticksOfXAxis[index];
          },
        },
        border: {
          color: "#64748b",
        },
      },
      y: {
        beginAtZero: true,
        title: {
          display: true,
          color: "#334155",
          font: {
            size: 12,
            lineHeight: 2,
          },
          text: content.y,
        },
        grid: {
          color: "#64748b",
        },
        border: {
          display: false,
        },
        ticks: {
          color: "#64748b",
          padding: 8,
          callback: function (value, index, ticks) {
            const { resultStepSize, unitToUse } = getStepSizeOfYTicks(
              ticks[ticks.length - 1].value,
              ticks.length,
            );
            return getYTicksByIndex(resultStepSize, index, unitToUse);
          },
        },
      },
    },
  };

  return [primeVueSetData, primeVueSetOption];
}

/**
 * Builds a horizontal bar chart for cases-by-task data.
 * @param {object} chartData - The chart data from the API.
 * @param {object} content - The axis label content.
 * @param {boolean} isSingle - Whether labels are single values.
 * @param {string} [xUnit='count'] - The x-axis unit.
 * @returns {Array} [chartData, chartOptions] tuple.
 */
function getCaseByTaskHorizontalBarChart(
  chartData,
  content,
  isSingle,
  xUnit = "count",
) {
  const labelPrimary = chartData.data[0].label;
  const labelSecondary = chartData.data[1].label;
  let primeVueSetData = {};
  let primeVueSetOption = {};

  const datasetsPrimary = chartData.data[0].data;
  const datasetsSecondary = chartData.data[1].data;
  datasetsPrimary.sort((a, b) => b.y - a.y);
  datasetsSecondary.sort((a, b) => {
    const indexA = datasetsPrimary.findIndex((item) => item.x === a.x);
    const indexB = datasetsPrimary.findIndex((item) => item.x === b.x);
    return indexA - indexB;
  });

  const xLabelData = datasetsPrimary.map((item) => item.x);
  const yDataPrimary = datasetsPrimary.map((item) => item.y);
  const yDataSecondary = datasetsSecondary.map((item) => item.y);

  primeVueSetData = {
    labels: xLabelData,
    datasets: [
      {
        label: labelPrimary,
        data: yDataPrimary,
        backgroundColor: colorPrimary,
      },
      {
        label: labelSecondary,
        data: yDataSecondary,
        backgroundColor: colorSecondary,
      },
    ],
  };
  primeVueSetOption = {
    indexAxis: "y",
    responsive: true,
    maintainAspectRatio: false,
    layout: {
      padding: {
        top: 16,
        left: 8,
        right: 8,
      },
    },
    plugins: {
      legend: false,
      tooltip: {
        mode: "index",
        titleFont: { weight: "normal" },
        callbacks: {},
      },
      title: {
        display: false,
      },
    },
    scales: {
      x: {
        title: {
          display: true,
          color: "#334155",
          font: {
            size: 12,
            lineHeight: 2,
          },
          text: content.x,
        },
        ticks: {
          display: true,
          maxRotation: 0,
          color: "#64748b",
          callback: function (value, index, ticks) {
            return value;
          },
        },
        grid: {
          color: "#64748b",
          tickLength: 0,
        },
        border: {
          display: false,
        },
      },
      y: {
        beginAtZero: true,
        type: "category",
        title: {
          display: true,
          color: "#334155",
          font: {
            size: 12,
            lineHeight: 2,
          },
          text: content.y,
        },
        ticks: {
          color: "#64748b",
          padding: 8,
        },
        grid: {
          display: false,
          color: "#64748b",
        },
        border: {
          display: false,
        },
      },
    },
  };
  switch (xUnit) {
    case "dummy":
    case "count":
    default:
      primeVueSetOption.scales.x.ticks.precision = 0;
      primeVueSetOption.plugins.tooltip.callbacks.label = function (context) {
        const value = context.parsed.x === null ? "n/a" : context.parsed.x;
        switch (context.datasetIndex) {
          case 0:
            return `${labelPrimary}: ${value}`;
          case 1:
            return `${labelSecondary}: ${value}`;
        }
      };
      break;
  }
  if (isSingle) {
    primeVueSetOption.plugins.tooltip.callbacks.title = function (context) {
      return `${content.y}: ${context[0].label}`;
    };
    primeVueSetOption.scales.y.ticks.callback = function (value, index, ticks) {
      const label = xLabelData[index];
      if (label) {
        return label.length > 21 ? `${label.substring(0, 18)}...` : label;
      }
    };
  } else {
    primeVueSetOption.plugins.tooltip.callbacks.title = function (context) {
      return `${content.y}: ${context[0].label.replace(",", " - ")}`;
    };
    primeVueSetOption.scales.y.ticks.callback = function (value, index, ticks) {
      const label = xLabelData[index];
      let labelStart = label[0];
      let labelEnd = label[1];

      labelStart =
        labelStart.length > 10
          ? `${labelStart.substring(0, 7)}...`
          : labelStart;
      labelEnd =
        labelEnd.length > 10 ? `${labelEnd.substring(0, 7)}...` : labelEnd;
      return labelStart + " - " + labelEnd;
    };
  }

  return [primeVueSetData, primeVueSetOption];
}

/**
 * Builds a horizontal bar chart for average process time data.
 * @param {object} chartData - The chart data from the API.
 * @param {object} content - The axis label content.
 * @param {boolean} isSingle - Whether labels are single values.
 * @param {string} [xUnit='date'] - The x-axis unit.
 * @returns {Array} [chartData, chartOptions] tuple.
 */
function getAvgProcessTimeHorizontalBarChart(
  chartData,
  content,
  isSingle,
  xUnit = "date",
) {
  const maxY = chartData.y_axis.max;
  const getSimpleTimeLabel = simpleTimeLabel;
  const getFollowTimeLabel = followTimeLabel;
  const labelPrimary = chartData.data[0].label;
  const labelSecondary = chartData.data[1].label;
  let primeVueSetData = {};
  let primeVueSetOption = {};

  const datasetsPrimary = chartData.data[0].data;
  const datasetsSecondary = chartData.data[1].data;
  datasetsPrimary.sort((a, b) => b.y - a.y);
  datasetsSecondary.sort((a, b) => {
    const indexA = datasetsPrimary.findIndex((item) => item.x === a.x);
    const indexB = datasetsPrimary.findIndex((item) => item.x === b.x);
    return indexA - indexB;
  });

  const xLabelData = datasetsPrimary.map((item) => item.x);
  const yDataPrimary = datasetsPrimary.map((item) => item.y);
  const yDataSecondary = datasetsSecondary.map((item) => item.y);

  primeVueSetData = {
    labels: xLabelData,
    datasets: [
      {
        label: labelPrimary,
        data: yDataPrimary,
        backgroundColor: colorPrimary,
      },
      {
        label: labelSecondary,
        data: yDataSecondary,
        backgroundColor: colorSecondary,
      },
    ],
  };
  primeVueSetOption = {
    indexAxis: "y",
    responsive: true,
    maintainAspectRatio: false,
    layout: {
      padding: {
        top: 16,
        left: 8,
        right: 8,
      },
    },
    plugins: {
      legend: false,
      tooltip: {
        mode: "index",
        titleFont: { weight: "normal" },
        callbacks: {},
      },
      title: {
        display: false,
      },
    },
    scales: {
      x: {
        title: {
          display: true,
          color: "#334155",
          font: {
            size: 12,
            lineHeight: 2,
          },
          text: content.x,
        },
        ticks: {
          display: true,
          maxRotation: 0,
          color: "#64748b",
        },
        grid: {
          color: "#64748b",
          tickLength: 0,
        },
        border: {
          display: false,
        },
      },
      y: {
        beginAtZero: true,
        type: "category",
        title: {
          display: true,
          color: "#334155",
          font: {
            size: 12,
            lineHeight: 2,
          },
          text: content.y,
        },
        ticks: {
          color: "#64748b",
          padding: 8,
        },
        grid: {
          display: false,
          color: "#64748b",
        },
        border: {
          display: false,
        },
      },
    },
  };
  switch (xUnit) {
    case "dummy":
    case "date":
    default:
      primeVueSetOption.plugins.tooltip.callbacks.label = function (context) {
        const value =
          context.parsed.x === null
            ? "n/a"
            : getSimpleTimeLabel(context.parsed.x, 2);
        switch (context.datasetIndex) {
          case 0:
            return `${labelPrimary}: ${value}`;
          case 1:
            return `${labelSecondary}: ${value}`;
        }
      };
      primeVueSetOption.scales.x.ticks.callback = function (
        value,
        index,
        ticks,
      ) {
        return getFollowTimeLabel(value, maxY, 1);
      };
      break;
  }
  if (isSingle) {
    primeVueSetOption.plugins.tooltip.callbacks.title = function (context) {
      return `${content.y}: ${context[0].label}`;
    };
    primeVueSetOption.scales.y.ticks.callback = function (value, index, ticks) {
      const label = xLabelData[index];
      if (label) {
        return label.length > 21 ? `${label.substring(0, 18)}...` : label;
      }
    };
  } else {
    primeVueSetOption.plugins.tooltip.callbacks.title = function (context) {
      return `${content.y}: ${context[0].label.replace(",", " - ")}`;
    };
    primeVueSetOption.scales.y.ticks.callback = function (value, index, ticks) {
      const label = xLabelData[index];
      let labelStart = label[0];
      let labelEnd = label[1];

      labelStart =
        labelStart.length > 10
          ? `${labelStart.substring(0, 7)}...`
          : labelStart;
      labelEnd =
        labelEnd.length > 10 ? `${labelEnd.substring(0, 7)}...` : labelEnd;
      return labelStart + " - " + labelEnd;
    };
  }

  return [primeVueSetData, primeVueSetOption];
}

onMounted(async () => {
  isLoading.value = true;
  try {
    const routeParams = route.params;
    const primaryType = routeParams.primaryType;
    const secondaryType = routeParams.secondaryType;
    const primaryId = routeParams.primaryId;
    const secondaryId = routeParams.secondaryId;
    const typeMap = {
      log: "log_id",
      filter: "filter_id",
    };
    const primaryTypeParam = typeMap[primaryType];
    const secondaryTypeParam = typeMap[secondaryType];
    const queryParams = [
      { [primaryTypeParam]: primaryId },
      { [secondaryTypeParam]: secondaryId },
    ];

    // Fetch Compare Data
    await compareStore.getCompare(queryParams);
    avgProcessTimeByTaskHeight.value = getHorizontalBarHeight(
      compareDashboardData.value.time.avg_process_time_by_task,
    );
    if (compareDashboardData.value.time.avg_waiting_time_by_edge !== null) {
      avgWaitingTimeByEdgeHeight.value = getHorizontalBarHeight(
        compareDashboardData.value.time.avg_waiting_time_by_edge,
      );
    }
    casesByTaskHeight.value = getHorizontalBarHeight(
      compareDashboardData.value.freq.cases_by_task,
    );
    // create chart
    [avgCycleTimeData.value, avgCycleTimeOptions.value] = getLineChart(
      compareDashboardData.value.time.avg_cycle_time,
      contentData.avgCycleTime,
      "date",
    );
    [avgCycleEfficiencyData.value, avgCycleEfficiencyOptions.value] =
      getBarChart(
        compareDashboardData.value.time.avg_cycle_efficiency,
        contentData.avgCycleEfficiency,
        "Cycle Eff",
      );
    [avgProcessTimeData.value, avgProcessTimeOptions.value] = getLineChart(
      compareDashboardData.value.time.avg_process_time,
      contentData.avgProcessTime,
      "date",
    );
    [avgProcessTimeByTaskData.value, avgProcessTimeByTaskOptions.value] =
      getAvgProcessTimeHorizontalBarChart(
        compareDashboardData.value.time.avg_process_time_by_task,
        contentData.avgProcessTimeByTask,
        true,
        "date",
      );
    [avgWaitingTimeData.value, avgWaitingTimeOptions.value] = getLineChart(
      compareDashboardData.value.time.avg_waiting_time,
      contentData.avgWaitingTime,
      "date",
    );
    if (compareDashboardData.value.time.avg_waiting_time_by_edge === null) {
      [avgWaitingTimeByEdgeData.value, avgWaitingTimeByEdgeOptions.value] = [
        null,
        null,
      ];
    } else {
      [avgWaitingTimeByEdgeData.value, avgWaitingTimeByEdgeOptions.value] =
        getHorizontalBarChart(
          compareDashboardData.value.time.avg_waiting_time_by_edge,
          contentData.avgWaitingTimeByEdge,
          false,
          "date",
        );
    }
    [freqData.value, freqOptions.value] = getLineChart(
      compareDashboardData.value.freq.cases,
      contentData.freq,
      "count",
    );
    [casesByTaskData.value, casesByTaskOptions.value] =
      getCaseByTaskHorizontalBarChart(
        compareDashboardData.value.freq.cases_by_task,
        contentData.casesByTask,
        true,
        "count",
      );
  } catch (error) {
    console.error("Failed to initialize compare dashboard:", error);
  } finally {
    isLoading.value = false;
  }
});
</script>
<style scoped>
@reference "../../../assets/tailwind.css";
.active {
  @apply text-primary;
}
</style>
