import { useTheme } from '@mui/material/styles';
import React, { memo, useCallback } from 'react';
import {
  Area,
  AreaChart,
  CartesianGrid,
  ResponsiveContainer,
  Tooltip,
  XAxis,
  YAxis
} from 'recharts';
import type { Margin } from 'recharts/types/util/types';
import type { ChartTooltipProps, ValueType, NameType } from '../../utils/charts';
import {
  ChartTooltip,
  fixChartsClasses,
  formatterData,
  formatterId,
  setDomainCalc,
  useTick
} from '../../utils/charts';
import type { Theme } from '../@styles/theme-provider';

export interface ChartAreaProps {
  data?: Record<NameType, ValueType>[];
  tooltip?: boolean;
  height?: number;
  dots?: boolean;
  domainMax?: number;
  domainCalc?: boolean;
  tickCountY?: number;
  dataKeyX?: ChartTooltipProps['format'];
  dataXFormat?: ChartTooltipProps['dataXFormat'];
  dataYFormat?: ChartTooltipProps['dataYFormat'];
  tooltipFormatter?: ChartTooltipProps['tooltipFormatter'];
  tooltipProps?: Partial<ChartTooltipProps>;
  chartConfig?: ChartTooltipProps['config'];
  chartMargin?: Margin;
  reverseOrder?: boolean;
}

const ChartArea = (props: ChartAreaProps) => {
  const theme = useTheme<Theme>();
  const {
    data = [],
    tooltip,
    height,
    dots,
    domainMax = 100,
    domainCalc = false,
    tickCountY,
    dataKeyX = 'date',
    dataXFormat = 'month',
    dataYFormat = '',
    tooltipFormatter,
    tooltipProps,
    chartConfig = [],
    chartMargin = { left: -24, right: 6 },
    reverseOrder = true
  } = props;

  const classes = fixChartsClasses();

  const tick = useTick();
  const formatterX = useCallback(
    (value: string) => formatterData(value, dataKeyX, dataXFormat),
    [dataKeyX, dataXFormat]
  );
  const formatterY = useCallback(
    (value: string) => formatterData(value, '', dataYFormat),
    [dataYFormat]
  );
  const setDomain = useCallback(
    (dataMax: number | undefined) => setDomainCalc(dataMax, domainCalc, domainMax),
    [domainMax, domainCalc]
  );

  if (reverseOrder) chartConfig.reverse();

  return (
    <ResponsiveContainer width="100%" height={height} className={classes.root}>
      <AreaChart data={data} margin={chartMargin}>
        <defs>
          {chartConfig?.map((entry, index) => (
            <linearGradient key={entry.id} id={formatterId(entry.id)} x1="0" y1="0" x2="0" y2="1">
              <stop
                offset="5%"
                stopColor={entry.color || theme.palette.specialColors[chartConfig.length - index]}
                stopOpacity={entry.stopOpacity?.[0] || 0.4}
              />
              <stop
                offset="95%"
                stopColor={entry.color || theme.palette.common.white}
                stopOpacity={entry.stopOpacity?.[1] || 0}
              />
            </linearGradient>
          ))}
        </defs>
        <CartesianGrid vertical={false} stroke={theme.palette.primary[300]} strokeDasharray="2 2" />
        <XAxis
          dataKey={dataKeyX}
          tick={tick}
          axisLine={false}
          tickLine={false}
          tickCount={data.length}
          minTickGap={1}
          tickFormatter={formatterX}
          tickMargin={8}
        />
        <YAxis
          tickCount={tickCountY}
          scale="linear"
          domain={[0, setDomain]}
          tick={tick}
          axisLine={false}
          tickLine={false}
          minTickGap={1}
          tickFormatter={formatterY}
          tickMargin={2}
          padding={{ top: 8 }}
          width={dataYFormat === 'percent' ? 70 : undefined}
        />
        {tooltip && (
          <Tooltip
            content={
              <ChartTooltip
                format={dataKeyX}
                dataXFormat={dataXFormat}
                dataYFormat={dataYFormat}
                tooltipFormatter={tooltipFormatter}
                config={chartConfig}
                disableReverse={false}
              />
            }
            {...tooltipProps}
          />
        )}
        {chartConfig?.map(({ show, ...entry }, index) => {
          if (!show) return null;
          const { color, id, disableStroke, areaProps } = entry;
          const stroke = color || theme.palette.specialColors[chartConfig.length - index];
          return (
            <Area
              type="monotone"
              key={`cell-${id}`}
              dataKey={id}
              stroke={stroke}
              fill={`url(#${formatterId(id)})`}
              strokeWidth={disableStroke ? 0 : 2}
              fillOpacity={1}
              dot={
                dots
                  ? {
                      stroke: stroke,
                      strokeWidth: 2,
                      r: 3,
                      fill: theme.palette.common.white
                    }
                  : false
              }
              activeDot={{
                stroke: stroke,
                strokeWidth: 2,
                r: 5,
                fill: theme.palette.common.white
              }}
              connectNulls
              {...areaProps}
            />
          );
        })}
      </AreaChart>
    </ResponsiveContainer>
  );
};

ChartArea.defaultProps = {
  data: [],
  chartConfig: [],
  tooltip: true,
  height: 325,
  dots: false,
  dataKeyX: 'date',
  domainCalc: false,
  domainMax: 100,
  tickCountY: 10,
  dataXFormat: 'month',
  dataYFormat: '',
  chartMargin: { left: -24, right: 6 }
};

const m = memo(ChartArea);
export { m as ChartArea };
