import { ref } from 'vue';
import type { Ref } from 'vue';
import { getHtmlLegendPlugin } from '@/services/ChartsCommonLegend';
import { formatWithThousandsSeprators } from '@/services/FormatUtilities';

import { addAlpha } from './ColorFunctions';
import { DoughnutData, DoughnutPlugin } from '@/types/DoughnutData';

export default function () {
  const doughnutRef: Ref = ref(null);
  const onHoverIndex: Ref<number | null> = ref(null);
  const backgroundColor: Ref<CanvasPattern[] | null> = ref(null);
  const centeredLabel: Ref = ref(null);

  function privateGetHtmlLegendPlugin(
    legendContainer: Ref,
    selectMode: Ref<boolean>,
    disableAccessibility: Ref<boolean>,
    patternsColors: Ref<string[]>,
    patternsList: Ref<
      ((
        hover: boolean,
        color: string,
        disableAccessibility: boolean
      ) => CanvasPattern)[]
    >,
    maxValueToDisplay: number,
    doughnutData: any,
    enableHoverFeature: Ref<boolean>
  ) {
    return getHtmlLegendPlugin(
      legendContainer,
      selectMode,
      onHoverIndex,
      disableAccessibility,
      patternsColors,
      patternsList,
      enableHoverFeature,
      maxValueToDisplay,
      doughnutData
    );
  }

  function getBackgroundColor(
    patternsColors: string[],
    patternsList: ((
      hover: boolean,
      color: string,
      disableAccessibility: boolean
    ) => CanvasPattern)[],
    disableAccessibility: boolean,
    enableHoverFeature: boolean
  ) {
    if (onHoverIndex.value !== null && enableHoverFeature) {
      return patternsList.map((pattern, index) =>
        onHoverIndex.value === index
          ? pattern(false, patternsColors[index], disableAccessibility)
          : pattern(true, patternsColors[index], disableAccessibility)
      );
    } else {
      return patternsList.map((pattern, index) =>
        pattern(false, patternsColors[index], disableAccessibility)
      );
    }
  }

  function getBorderColor(
    patternsColors: string[],
    enableHoverFeature: boolean
  ): string[] {
    if (onHoverIndex.value !== null && enableHoverFeature) {
      return patternsColors.map((color, index) =>
        onHoverIndex.value === index ? color : addAlpha(color, 0.2)
      );
    } else {
      return patternsColors;
    }
  }

  function getOnHoverOptions() {
    return (_ignore: unknown, activeElements: Array<any>): void => {
      if (activeElements[0] !== undefined) {
        onHoverIndex.value = activeElements[0].element.$context.index;
      } else {
        onHoverIndex.value = null;
      }
    };
  }

  const getFormatedText = (str: string) => {
    return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
  };

  function getCenteredLabelPlugin(
    doughnutData: DoughnutData[]
  ): DoughnutPlugin {
    return {
      id: 'centeredLabelPlugin',
      afterDatasetDraw: (chart) => {
        const selectedIndexes: Number[] = [];
        const arcElements = chart.getDatasetMeta(0).data;

        arcElements.forEach((arcElement: any, index: Number) => {
          if (arcElement.startAngle !== arcElement.endAngle) {
            selectedIndexes.push(index);
          }
        });

        const total = (chart as any)._metasets[0]?._dataset?.raw_value
          ?.filter((_: any, index: Number) => selectedIndexes.includes(index))
          .reduce((acc: number, currentValue: any) => acc + currentValue, 0);

        const unit = doughnutData[0]?.unit ?? '';
        centeredLabel.value = `${formatWithThousandsSeprators(total)}${unit}`;
      }
    };
  }

  function getDoughnutLabels(
    labels: string[],
    data: DoughnutData[],
    maxValues: number,
    othersLabel: string
  ) {
    let truncatedLabels = labels.slice(0);
    let truncatedData = data.slice(0);
    if (labels.length > maxValues) {
      truncatedData = groupDataAfterNthValue(data, maxValues);
      truncatedLabels = truncatedLabels.slice(0, maxValues - 1);
      truncatedLabels.push(othersLabel);
    }
    return truncatedLabels.map(
      (label: string, index: number) =>
        `${getFormatedText(label)} (${formatWithThousandsSeprators(
          truncatedData[index]?.rate as number
        )} %)`
    );
  }

  function groupDataAfterNthValue(data: DoughnutData[], maxValues: number) {
    if (maxValues < 1) {
      return data;
    }
    let truncatedData = data.slice(0);
    if (data.length > maxValues) {
      truncatedData = truncatedData.slice(0, maxValues);
      truncatedData[maxValues - 1] = data.slice(maxValues).reduce(
        (result, current) => {
          result.rate += current.rate;
          result.value += current.value;
          return result;
        },
        { ...data[maxValues - 1] }
      );
    }
    return truncatedData;
  }

  return {
    onHoverIndex,
    privateGetHtmlLegendPlugin,
    getOnHoverOptions,
    groupDataAfterNthValue,
    getDoughnutLabels,
    getBackgroundColor,
    getFormatedText,
    getBorderColor,
    backgroundColor,
    doughnutRef,
    getCenteredLabelPlugin,
    centeredLabel
  };
}
