/* eslint-disable react/jsx-props-no-spreading */
import React, { FC, useEffect, useRef, useState } from 'react';
import ChartJS from 'chart.js/auto';
import cloneDeep from 'lodash/cloneDeep';
import ReactDOMServer from 'react-dom/server';
import { addTransparencyToColor } from '../../utils';
import { Wrapper } from '../../Wrapper';
import { ChartDoughnutProps, ChartDoughnutDataSet, ContextType } from '../types.d';
import { useTheme, ThemeObject } from '../../Theme';

const CHART_TYPE = 'doughnut';

const getOrCreateTooltip = (chart: ChartJS, theme: ThemeObject) => {
  let tooltipEl = chart.canvas.parentElement !== null ? chart.canvas.parentElement.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;

    if (chart.canvas.parentNode !== null) chart.canvas.parentNode.appendChild(tooltipEl);
  }

  return tooltipEl;
};

const generateData = (datasets: ChartDoughnutDataSet[], spacingWidth: number, theme: ThemeObject) => {
  const dataWithSpacing = datasets.reduce((acc, dataset, i) => {
    const firstColor = dataset.backgroundColor[0];
    const transparencyForLightTheme = '16';
    const transparencyForDarkTheme = '33';
    const backgroundColors = dataset.backgroundColor.map((color) => {
      if (color === '') return addTransparencyToColor(firstColor, theme, transparencyForLightTheme, transparencyForDarkTheme);
      return color;
    });
    const datasetCopy = cloneDeep(dataset);
    datasetCopy.backgroundColor = backgroundColors;

    if (i === 0 || i % 2 !== 0)
      acc.push(datasetCopy, { data: [0], weight: spacingWidth, backgroundColor: [`${theme.background.light}`] });
    else acc.push(datasetCopy);
    return acc;
  }, [] as ChartDoughnutDataSet[]);

  return { datasets: dataWithSpacing };
};

const createLegend = (data: ChartDoughnutDataSet[], theme: ThemeObject) => {
  const legend = data.map((dataset, index) => {
    if (!dataset.tooltip) return null;
    return dataset.tooltip.map((e, i) => (
      <div key={e.label + e.value + i.toString() + index.toString()} className="legend-line">
        <div className="icon">
          <span style={{ background: dataset.backgroundColor[i] }} />
        </div>
        <div className="label" style={{ color: theme.text.main }}>
          {e.label}
        </div>
        <div className="value" style={{ color: theme.text.secondary }}>
          {e.value}
        </div>
      </div>
    ));
  });
  return legend;
};

export const Doughnut: FC<ChartDoughnutProps> = (props) => {
  const theme = useTheme();
  const chartContainer = useRef(null);
  const { data, wrapperProps, hideLegend, hideTooltip } = props;
  const { datasets, spacingWidth = 3, centerCutOut = '75%', innerContainerContent, doughnutWrapperProps } = data;

  const [isRebuildingCanvas, setIsRebuildingCanvas] = useState(false);
  const legend = createLegend(datasets, theme);

  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 chartDoughnutData = generateData(datasets, spacingWidth, theme);

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

      const { dataIndex, datasetIndex } = tooltip.dataPoints[0];
      const dataset = tooltip.dataPoints[0].dataset as ChartDoughnutDataSet;

      const label = dataset.tooltip && dataset.tooltip[dataIndex] ? dataset.tooltip[dataIndex].label : null;
      const value = dataset.tooltip && dataset.tooltip[dataIndex] ? dataset.tooltip[dataIndex].value : null;

      // Hide if no tooltip
      const isHideTooltip = tooltip.opacity === 0 || label === null || value === null || hideTooltip;
      if (isHideTooltip) {
        tooltipEl.style.display = 'none';
        return;
      }

      const arcs = legend[datasetIndex / 2];
      if (arcs !== null) {
        const html = ReactDOMServer.renderToString(arcs[dataIndex]);
        tooltipEl.innerHTML = html;
      }

      tooltipEl.style.display = 'block';

      const centerOfChart = chart.width / 2;
      tooltipEl.style.left = `${tooltip.caretX}px`;
      tooltipEl.style.top = `${tooltip.caretY}px`;
      if (tooltip.caretX > centerOfChart) {
        tooltipEl.classList.add('right-arrow');
        tooltipEl.classList.remove('left-arrow');
      } else {
        tooltipEl.classList.add('left-arrow');
        tooltipEl.classList.remove('right-arrow');
      }

      const labelElement = tooltipEl.querySelector('.label');
      if (labelElement !== null) labelElement.setAttribute('style', `color: ${theme.text.inverse}`);
      const valueElement = tooltipEl.querySelector('.value');
      if (valueElement !== null) valueElement.setAttribute('style', `color: ${theme.text.inverse}`);
    };

    const options = {
      responsive: true,
      cutout: centerCutOut,
      plugins: {
        legend: {
          display: false,
        },
        tooltip: {
          enabled: false,
          external: externalTooltipHandler,
        },
      },
    };

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

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

  return (
    <Wrapper
      width="224px"
      shadow="0 0 0 0"
      borderRadius="0"
      padding="15px"
      {...wrapperProps}
      className={`${wrapperProps && wrapperProps.className ? wrapperProps.className : ''} chart-doughnut-wrapper`}
    >
      <Wrapper
        width="65%"
        shadow="0 0 0 0"
        borderRadius="0"
        margin="0 0 20px 0"
        {...doughnutWrapperProps}
        className={`${
          doughnutWrapperProps && doughnutWrapperProps.className ? doughnutWrapperProps.className : ''
        } chart-doughnut-style`}
      >
        <div>
          <canvas ref={chartContainer} />
        </div>
        {innerContainerContent ? (
          <Wrapper className="inner-container" borderRadius="0" shadow="0 0 0 0">
            <Wrapper
              className="inner-background"
              width={centerCutOut}
              height={centerCutOut}
              backgroundColor={innerContainerContent.backgroundColor}
              borderRadius="50%"
              shadow="0 0 0 0"
            />
            <div className="inner-content">
              <span className="title" style={{ color: theme.text.main }}>
                {innerContainerContent.title}
              </span>
              <span className="text" style={{ color: theme.text.hint }}>
                {innerContainerContent.text}
              </span>
            </div>
          </Wrapper>
        ) : null}
      </Wrapper>
      {!hideLegend ? (
        <Wrapper borderRadius="0" shadow="0 0 0 0" className="legend-wrapper">
          {legend}
        </Wrapper>
      ) : null}
    </Wrapper>
  );
};
