<template>
  <Chart
    type="line"
    :data="primeVueSetDataState"
    :options="primeVueSetOptionsState"
    class="h-96"
  />
</template>

<script setup>
// The Lucia project.
// Copyright 2024-2026 DSP, inc.  All rights reserved.
// Authors:
//   cindy.chang@dsp.im (Cindy Chang), 2024/5/30
//   imacat.yang@dsp.im (imacat), 2023/9/23
/**
 * @module views/Discover/Performance/FreqChart
 *   Frequency chart component displaying activity
 *   occurrence data with Chart.js bar charts.
 */

import { ref, onMounted } from "vue";
import {
  setTimeStringFormatBaseOnTimeDifference,
  mapTimestampToAxisTicksByFormat,
} from "@/module/timeLabel.js";

const knownScaleLineChartOptions = {
  x: {
    type: "time",
    title: {
      display: true,
      color: "#334155",
      font: {
        size: 12,
        lineHeight: 2,
      },
    },
    time: {
      displayFormats: {
        second: "h:mm:ss", // ex: 1:11:11
        minute: "M/d h:mm", // ex: 1/1 1:11
        hour: "M/d h:mm", // ex: 1/1 1:11
        day: "M/d h", // ex: 1/1 1
        month: "y/M/d", // ex: 1911/1/1
      },
    },
    ticks: {
      display: true,
      maxRotation: 0, // Do not rotate labels (range: 0~50)
      color: "#64748b",
      source: "labels", // Dynamically display label count proportionally
    },
    border: {
      color: "#64748b",
    },
    grid: {
      tickLength: 0, // Prevent grid lines from extending beyond the axis
    },
  },
  y: {
    beginAtZero: true, // Scale includes 0
    title: {
      display: true,
      color: "#334155",
      font: {
        size: 12,
        lineHeight: 2,
      },
    },
    ticks: {
      color: "#64748b",
      padding: 8,
    },
    grid: {
      color: "#64748b",
    },
    border: {
      display: false, // Hide the extra border line on the left side
    },
  },
};

const props = defineProps({
  chartData: {
    type: Object,
  },
  content: {
    type: Object,
  },
  yUnit: {
    type: String,
  },
  pageName: {
    type: String,
  },
});

const primeVueSetDataState = ref(null);
const primeVueSetOptionsState = ref(null);
const colorPrimary = ref("#0099FF");
const colorSecondary = ref("#FFAA44");

/**
 * Compare page and Performance have this same function.
 * @param whichScaleObj PrimeVue scale option object to reference to
 * @param customizeOptions
 * @param customizeOptions.content
 * @param customizeOptions.ticksOfXAxis
 */
const getCustomizedScaleOption = (
  whichScaleObj,
  { customizeOptions: { content, ticksOfXAxis } },
) => {
  let resultScaleObj;
  resultScaleObj = customizeScaleChartOptionTitleByContent(
    whichScaleObj,
    content,
  );
  resultScaleObj = customizeScaleChartOptionTicks(resultScaleObj, ticksOfXAxis);
  return resultScaleObj;
};

/**
 * Compare page and Performance have this same function.
 * @param {object} scaleObjectToAlter this object follows the format of prive vue chart
 * @param {Array<string>} ticksOfXAxis For example, ['05/06', '05,07', '05/08']
 * or ['08:03:01', '08:11:18', '09:03:41', ], and so on.
 */
const customizeScaleChartOptionTicks = (scaleObjectToAlter, ticksOfXAxis) => {
  return {
    ...scaleObjectToAlter,
    x: {
      ...scaleObjectToAlter.x,
      ticks: {
        ...scaleObjectToAlter.x.ticks,
        callback: function (value, index) {
          // Customize x-axis time ticks based on different intervals
          return ticksOfXAxis[index];
        },
      },
    },
  };
};

/** Compare page and Performance have this same function.
 * Customizes a base tooltip object using the content data.
 * The object order is known to be: x, then title, then text.
 * This function alters the title property of known scales object of Chart option
 * This is based on the fact that we know the order must be x -> title -> text.
 * @param {object} whichScaleObj PrimeVue scale option object to reference to
 * @param content whose property includes x and y and stand for titles
 *
 * @returns { object } an object modified with two titles
 */
const customizeScaleChartOptionTitleByContent = (whichScaleObj, content) => {
  if (!content) {
    // Early return
    return whichScaleObj;
  }

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

/**
 * Builds the PrimeVue line chart data and options configuration.
 * @param {object} chartData - The chart data from the API.
 * @param {object} content - The axis label content.
 * @param {string} pageName - 'Compare' or page identifier.
 */
const getLineChartPrimeVueSetting = (chartData, content, pageName) => {
  let datasetsArr;
  let datasets;
  let datasetsPrimary; // For Compare page case
  let datasetsSecondary; // For Compare page case
  const minX = chartData?.x_axis?.min;
  const maxX = chartData?.x_axis?.max;
  let xData;
  let primeVueSetData = {};
  let primeVueSetOption = {};

  // Consider the dimension of chartData.data
  // When handling the Compare page case
  if (pageName === "Compare") {
    datasetsPrimary = chartData.data[0].data;
    datasetsSecondary = chartData.data[1].data;

    datasetsArr = [
      {
        label: chartData.data[0].label,
        data: datasetsPrimary,
        fill: false,
        tension: 0, // Bezier curve tension
        borderColor: colorPrimary,
        pointBackgroundColor: colorPrimary,
      },
      {
        label: chartData.data[1].label,
        data: datasetsSecondary,
        fill: false,
        tension: 0, // Bezier curve tension
        borderColor: colorSecondary,
        pointBackgroundColor: colorSecondary,
      },
    ];
    xData = chartData.data[0].data.map((item) => new Date(item.x).getTime());
  } else {
    datasets = chartData.data;
    datasetsArr = [
      {
        label: content.title,
        data: datasets,
        fill: false,
        tension: 0, // Bezier curve tension
        borderColor: "#0099FF",
      },
    ];
    xData = chartData.data.map((item) => new Date(item.x).getTime());
  }

  // Customize X axis ticks due to different differences between min and max of data group
  // Compare page and Performance page share the same logic
  const formatToSet = setTimeStringFormatBaseOnTimeDifference(minX, maxX);
  const ticksOfXAxis = mapTimestampToAxisTicksByFormat(xData, formatToSet);
  const customizedScaleOption = getCustomizedScaleOption(
    knownScaleLineChartOptions,
    {
      customizeOptions: {
        content,
        ticksOfXAxis,
      },
    },
  );

  primeVueSetData = {
    labels: xData,
    datasets: datasetsArr,
  };
  primeVueSetOption = {
    responsive: true,
    maintainAspectRatio: false,
    layout: {
      padding: {
        top: 16,
        left: 8,
        right: 8,
      },
    },
    plugins: {
      legend: false, // Legend
      tooltip: {
        displayColors: true,
        titleFont: { weight: "normal" },
        callbacks: {
          label: function (tooltipItem) {
            // Get the data
            const label = tooltipItem.dataset.label || "";

            // Build the tooltip label with dataset color indicator
            return `${label}: ${tooltipItem.parsed.y}`; // Use Unicode block to represent color
          },
        },
      },
      title: {
        display: false,
      },
    },
    scales: customizedScaleOption,
  };

  primeVueSetOption.scales.y.ticks.precision = 0; // Show 0 decimal places on y-axis
  primeVueSetOption.scales.y.ticks.callback = function (value, index, ticks) {
    return value; // Y-axis ticks here have no time unit suffix
  };
  primeVueSetDataState.value = primeVueSetData;
  primeVueSetOptionsState.value = primeVueSetOption;
};

onMounted(() => {
  getLineChartPrimeVueSetting(props.chartData, props.content, props.pageName);
});
</script>
