import React, { useCallback, useMemo, ReactNode } from 'react';
import Typography from '@mui/material/Typography';
import Grid from '@mui/material/Grid';
import Box from '@mui/material/Box';
import { AreaProps } from 'recharts';
import type { TooltipProps as BaseTooltipProps } from 'recharts';

import { formatterData, formattedLabel } from '../formatters/formatters';
import createClasses from './styles';
import type { ValueType, NameType } from './index';

export type RechartsTooltipProps = BaseTooltipProps<ValueType, NameType>;

export type TooltipFormatterType = (item: PayloadItem, index: number) => PayloadItem;

type ArrayElement<A> = A extends readonly (infer T)[] ? T : never;

export type PayloadItem = ArrayElement<RechartsTooltipProps['payload']>;

export interface ChartTooltipProps extends RechartsTooltipProps {
  active?: boolean;
  label?: string;
  format?: string;
  dataXFormat?: string;
  dataYFormat?: string;
  tooltipFormatter?: TooltipFormatterType;
  valuePostfix?: string;
  disableReverse?: boolean;
  config: {
    id: string;
    show: boolean;
    name?: string;
    color?: string;
    disableStroke?: boolean;
    areaProps?: Omit<AreaProps, 'ref' | 'key' | 'dataKey' | 'dot' | 'activeDot'>;
    stopOpacity?: [number, number];
  }[];
  withTitleValue?: boolean;
  withTitle?: string;
}

const ChartTooltip = (props: ChartTooltipProps) => {
  const {
    payload,
    active,
    label,
    format,
    dataXFormat,
    dataYFormat,
    tooltipFormatter,
    labelFormatter,
    config,
    valuePostfix,
    disableReverse = false,
    withTitleValue,
    withTitle
  } = props;

  const showTooltip = useMemo(() => active && payload && Array.isArray(payload), [active, payload]);

  const classes = createClasses();

  const labelFormat = useMemo(() => {
    return labelFormatter && payload
      ? labelFormatter(label, payload)
      : formattedLabel(label || '', format, dataXFormat);
  }, [format, dataXFormat, label, labelFormatter, payload]);

  const valueFormat = useCallback(value => formatterData(value, '', dataYFormat), [dataYFormat]);

  const findNamebyId = useCallback(
    (key: string) => config?.find(({ id }) => id === key)?.name,
    [config]
  );

  const payloadItems = useMemo(
    () =>
      (disableReverse ? payload : payload?.slice().reverse())?.map((value, index) =>
        tooltipFormatter ? tooltipFormatter(value, index) : value
      ),
    [disableReverse, payload, tooltipFormatter]
  );

  const titleValue = payload?.reduce((acc, cur) => {
    return acc + (cur.value as number);
  }, 0);

  if (showTooltip) {
    return (
      <Grid container direction="column" className={classes.root}>
        {withTitle ? (
          <>
            <Typography component="h3" className={classes.title} data-testid="label">
              {withTitleValue ? `${withTitle} (${titleValue})` : withTitle}
            </Typography>
            <Typography className={classes.subTitle}>{labelFormat}</Typography>
          </>
        ) : (
          <Typography component="h3" className={classes.title} data-testid="label">
            {withTitleValue ? `${labelFormat} (${titleValue})` : labelFormat}
          </Typography>
        )}
        {payloadItems?.map((item, index) => (
          <Typography className={classes.item} align="center" key={item?.name}>
            <Typography component="span">
              <Box
                component="span"
                className={classes.square}
                data-testid={'square-' + index}
                style={{ backgroundColor: item?.color }}
              />
              <Typography component="span" className={classes.name} data-testid={'name-' + index}>
                {item.name && findNamebyId(item.name)}:
              </Typography>
            </Typography>

            <Typography component="span" className={classes.data} data-testid={'value-' + index}>
              {valueFormat(item.value)}
              {valuePostfix}
            </Typography>
          </Typography>
        ))}
      </Grid>
    );
  }

  return null;
};

ChartTooltip.defaultProps = {
  payload: [],
  active: false,
  label: '',
  format: 'date',
  dataXFormat: '',
  dataYFormat: '',
  config: [],
  valuePostfix: ''
};

export default ChartTooltip;
