import { reactive, ref } from 'vue';
import type { Ref } from 'vue';
import { getHtmlLegendPlugin } from './ChartsCommonLegend';
import PatternFunctions from './PatternFunctions';
import { addAlpha } from './ColorFunctions';
import { getVirtualNodeHeight } from 'mermaid/dist/diagrams/timeline/svgDraw';

const { getPatternIndexWithShift } = PatternFunctions();

interface Dataset {
  data: number[];
  label: any;
  stack?: number;
}

export default function () {
  const borderWidth = ref(3);
  const barChartRef = ref(null as any);
  const onHoverIndex: { dataSetIndex: number; columnIndex: number } = reactive({
    dataSetIndex: -1,
    columnIndex: -1
  });

  function privateGetHtmlLegendPlugin(
    legendContainer: Ref,
    selectMode: Ref<boolean>,
    disableAccessibility: Ref<boolean>,
    patternsColors: Ref<string[]>,
    patternsList: Ref<
      ((
        hover: boolean,
        color: string,
        disableAccessibility: boolean
      ) => CanvasPattern)[]
    >,
    enableHoverFeature: Ref<boolean>
  ) {
    return getHtmlLegendPlugin(
      legendContainer,
      selectMode,
      onHoverIndex,
      disableAccessibility,
      patternsColors,
      patternsList,
      enableHoverFeature
    );
  }
  // Hack to force the chart to reload on Hover
  function reloadChart() {
    borderWidth.value = 4;
    borderWidth.value = 3;
  }

  function getStackedDatasets(
    datasets: Dataset[],
    stackDatasets: boolean,
    disableAccessibility: boolean,
    patternsColors: string[],
    patternsList: ((
      hover: boolean,
      color: string,
      disableAccessibility: boolean
    ) => CanvasPattern)[],
    patternShifting?: number
  ) {
    // Hack to force refresh
    const borderWithValue = borderWidth.value;
    return datasets.map((dataset, datasetIndex) => {
      return {
        borderColor: function (context: any) {
          return disableAccessibility
            ? '#00000000'
            : getBorderColor(
                datasetIndex,
                context.index,
                patternsColors,
                patternShifting
              );
        },
        backgroundColor: function (context: any) {
          return getPattern(
            datasetIndex,
            context.index,
            disableAccessibility,
            patternsColors,
            patternsList,
            patternShifting
          );
        },
        borderWidth: function () {
          return disableAccessibility ? 1 : borderWithValue;
        },

        data: dataset.data,
        label: dataset.label,
        stack: `Stack ${stackDatasets ? dataset.stack : datasetIndex}`
      };
    });
  }

  function getDatasets(
    firstDataSet: Dataset,
    secondDataSet: Dataset,
    patternsColors: string[],
    patternsList: ((
      hover: boolean,
      color: string,
      disableAccessibility: boolean
    ) => CanvasPattern)[],
    disableAccessibility: boolean
  ) {
    return getStackedDatasets(
      [firstDataSet, secondDataSet],
      false,
      disableAccessibility,
      patternsColors,
      patternsList
    );
  }

  function getBorderColor(
    dataSetIndex: number,
    contextIndex: number,
    patternsColors: string[],
    patternShifting?: number
  ) {
    const index = getPatternIndexWithShift(dataSetIndex, patternShifting);
    if (displayFullOpacity(dataSetIndex, contextIndex)) {
      return patternsColors[index];
    } else {
      return addAlpha(patternsColors[index], 0.2);
    }
  }

  function getPattern(
    dataSetIndex: number,
    contextIndex: number,
    disableAccessibility: boolean,
    patternsColors: string[],
    patternsList: ((
      hover: boolean,
      color: string,
      disableAccessibility: boolean
    ) => CanvasPattern)[],
    patternShifting?: number
  ) {
    const index = getPatternIndexWithShift(dataSetIndex, patternShifting);
    if (displayFullOpacity(dataSetIndex, contextIndex)) {
      return patternsList[index](
        false,
        patternsColors[index],
        disableAccessibility
      );
    } else {
      return patternsList[index](
        true,
        patternsColors[index],
        disableAccessibility
      );
    }
  }

  function nothingHovered(): boolean {
    return onHoverIndex.dataSetIndex < 0;
  }

  function columnHovered(dataSetIndex: number, contextIndex: number): boolean {
    return (
      onHoverIndex.dataSetIndex === dataSetIndex &&
      onHoverIndex.columnIndex === contextIndex
    );
  }

  function legendHovered(dataSetIndex: number): boolean {
    return (
      onHoverIndex.dataSetIndex === dataSetIndex && onHoverIndex.columnIndex < 0
    );
  }

  function displayFullOpacity(
    dataSetIndex: number,
    contextIndex: number
  ): boolean {
    return (
      nothingHovered() ||
      columnHovered(dataSetIndex, contextIndex) ||
      legendHovered(dataSetIndex)
    );
  }

  function resetOnHoverIndex() {
    onHoverIndex.dataSetIndex = -1;
    onHoverIndex.columnIndex = -1;
  }

  function getOnHoverOptions() {
    return (
      _ignore: unknown,
      activeElements: Array<{ index: number; datasetIndex: number }>
    ) => {
      if (activeElements[0] !== undefined) {
        onHoverIndex.dataSetIndex = activeElements[0].datasetIndex;
        onHoverIndex.columnIndex = activeElements[0].index;
      } else {
        resetOnHoverIndex();
      }
    };
  }

  return {
    onHoverIndex,
    reloadChart,
    getDatasets,
    getStackedDatasets,
    getOnHoverOptions,
    getBorderColor,
    getPattern,
    privateGetHtmlLegendPlugin,
    getPatternIndexWithShift,
    barChartRef,
    borderWidth
  };
}
