/* eslint-disable react/jsx-props-no-spreading */
import React, { FC, useEffect, useRef, useState } from 'react';
import ReactDOMServer from 'react-dom/server';
import ChartJS, { ScriptableScaleContext } from 'chart.js/auto';
import { ChartLineProps, ChartLineDataSet, ContextType } from '../types.d';
import { useTheme, ThemeObject } from '../../Theme';

const getOrCreateTooltip = (chart: ChartJS, theme: ThemeObject) => {
  let tooltipEl = chart.canvas.parentNode !== null ? chart.canvas.parentNode.querySelector('div') : null;

  if (!tooltipEl) {
    tooltipEl = document.createElement('div');
    tooltipEl.classList.add('custom-tooltip');
    tooltipEl.style.background = theme.background.inverse;
    tooltipEl.style.borderColor = theme.background.inverse;
    tooltipEl.style.color = theme.text.inverse;

    const table = document.createElement('table');
    tooltipEl.appendChild(table);
    if (chart.canvas.parentNode !== null) chart.canvas.parentNode.appendChild(tooltipEl);
  }

  return tooltipEl;
};

const getData = (dataSets: ChartLineDataSet[], labelValuesX: string[], theme: ThemeObject) => {
  const datasets = dataSets.map((dataSet) => {
    return {
      label: dataSet.label,
      data: dataSet.points.map((point) => point.value),
      pointHoverRadius: 10,
      pointHoverBorderWidth: 3,
      pointBorderColor: 'transparent',
      pointBackgroundColor: 'transparent',
      pointHoverBorderColor: theme.background.light,
      pointHoverBackgroundColor: theme.pallet[dataSet.color],
      borderColor: theme.pallet[dataSet.color],
      backgroundColor: theme.pallet[dataSet.color],
      lineTension: dataSet.lineTension,
    };
  });
  return { labels: labelValuesX, datasets };
};

export const Line: FC<ChartLineProps> = (props) => {
  const type = 'line';
  const theme = useTheme();
  const chartContainer = useRef(null);
  const { dataSets, nameAxisX = '', nameAxisY = '', labelValuesY, labelValuesX, valuesXForTooltip, tooltipTitle } = props;

  const [isRebuildingCanvas, setIsRebuildingCanvas] = useState(false);

  useEffect(() => {
    const tooltips = document.querySelectorAll('.custom-tooltip');
    Array.from(tooltips).forEach((e) => e.remove());
    setIsRebuildingCanvas(true);
  }, [theme.type]);

  useEffect(() => {
    if (isRebuildingCanvas) setIsRebuildingCanvas(false);
  }, [isRebuildingCanvas]);

  useEffect(() => {
    const ctx = chartContainer !== null ? chartContainer.current : null;
    if (isRebuildingCanvas || ctx === null) return;

    const data = getData(dataSets, labelValuesX, theme);

    const externalTooltipHandler = (context: ContextType) => {
      const { chart, tooltip } = context;
      const tooltipEl = getOrCreateTooltip(chart, theme);

      // Hide if no tooltip
      if (tooltip.opacity === 0) {
        tooltipEl.style.display = 'none';
        return;
      }

      const lineIndex = tooltip.dataPoints[0].datasetIndex;
      const pointIndex = tooltip.dataPoints[0].dataIndex;

      const title = (
        <tr className="chart-line-tooltip-title">
          <td colSpan={3}>
            <span className="bold">{tooltipTitle}</span>
            {` (${valuesXForTooltip[pointIndex]})`}
          </td>
        </tr>
      );
      const jsxElements = dataSets[lineIndex].points[pointIndex].tooltipData.map((dataLine) => (
        <tr>
          {dataLine.map((element, i) => {
            if (i === 1) return <td className="chart-line-tooltip-gray-text">{element}</td>;
            return <td>{element}</td>;
          })}
        </tr>
      ));
      jsxElements.unshift(title);

      const tableRoot = tooltipEl.querySelector('table');
      if (tableRoot !== null) {
        let html = '';
        for (let i = 0; i < jsxElements.length; i += 1) html += ReactDOMServer.renderToString(jsxElements[i]);
        tableRoot.innerHTML = html;
      }

      const { offsetLeft: positionX, offsetTop: positionY } = chart.canvas;
      tooltipEl.style.display = 'block';
      tooltipEl.style.left = `${positionX + tooltip.caretX}px`;
      tooltipEl.style.top = `${positionY + tooltip.caretY}px`;
      const tdElements = tooltipEl.querySelectorAll('.chart-line-tooltip-gray-text');
      tdElements.forEach((e) => e.setAttribute('style', `color: ${theme.text.secondary}`));
    };

    const options = {
      responsive: true,
      plugins: {
        title: {
          display: false,
        },
        legend: {
          display: false,
        },
        tooltip: {
          enabled: false,
          external: externalTooltipHandler,
        },
      },
      scales: {
        x: {
          title: {
            display: true,
            text: nameAxisX,
          },
          grid: {
            color(context: ScriptableScaleContext) {
              return context.tick.label !== '' ? theme.pallet.gray : 'transparent';
            },
            borderColor: theme.pallet.gray,
          },
          ticks: {
            color: theme.text.hint,
            stepSize: 1,
            maxRotation: 0,
            autoSkip: false,
          },
        },
        y: {
          title: {
            display: true,
            text: nameAxisY,
          },
          grid: {
            display: false,
            borderColor: theme.pallet.gray,
          },
          min: 0,
          ticks: {
            callback: (value: string | number, index: number) => {
              return labelValuesY[index] !== '' ? labelValuesY[index] : '';
            },
            color: theme.text.hint,
            stepSize: 1,
            autoSkip: false,
          },
        },
      },
    };

    const newChartInstance = new ChartJS(ctx, { type, data, options });

    // eslint-disable-next-line consistent-return
    return () => newChartInstance.destroy();
  }, [chartContainer, isRebuildingCanvas, dataSets, labelValuesX]);

  return (
    <div>
      <canvas ref={chartContainer} />
    </div>
  );
};
