import React, { useCallback, useMemo, useState } from 'react';
import type { LayoutChangeEvent, ViewStyle } from 'react-native';
import ChartFrame from '../shared/ChartFrame';
import useCustomColor from '../shared/hooks/useCustomColor';
import {
  createNiceScale,
  maxValueFromDataSet,
  minValueFromDataSet,
} from '../shared/niceNumbers';
import { StyledLineChartWrapper } from '../StyledChart';
import type {
  AxisCoordinates,
  DataValue,
  HeaderConfig,
  Series,
  StyleConfig,
  XAxisConfig,
  YAxisConfig,
} from '../types';
import Line from './Line';

export interface LineChartProps {
  /**
   * The data to be displayed in the chart. Each item represents a series.
   */
  data: Array<Series<Array<DataValue>>>;
  /**
   * Optional configuration for the Y axis.
   */
  yAxisConfig?: YAxisConfig;
  /**
   * Optional configuration for the X axis.
   */
  xAxisConfig?: XAxisConfig;
  /**
   * Additional style for the root View.
   */
  style?: ViewStyle;
  /**
   * Testing id of the component.
   */
  testID?: string;
  /**
   * Header configuration for the chart.
   */
  headerConfig?: HeaderConfig;
  /**
   * Text to display when the chart is empty.
   */
  emptyText?: string;
  /**
   * * styleConfig use to custom the style of the chart.
   * * styleConfig must be an object:
   *    * color?: use to custom the legend colors.
   */
  styleConfig?: StyleConfig;
}

const LineChart = ({
  data,
  yAxisConfig,
  xAxisConfig,
  style,
  testID,
  headerConfig,
  emptyText,
  styleConfig,
}: LineChartProps) => {
  const [chartSize, setChartSize] = useState({ width: 0, height: 0 });

  const colorScale = useCustomColor({
    data,
    seriesConfig: styleConfig?.series,
  });

  const niceValues = useMemo(() => {
    const maxDataValue = maxValueFromDataSet(data);
    const minDataValue = minValueFromDataSet(data);
    return createNiceScale(minDataValue, maxDataValue);
  }, [data]);

  const yAxisStep = yAxisConfig?.step ?? niceValues.tickSpacing;
  const yAxisInterval = yAxisConfig?.tick?.interval ?? yAxisStep;

  const calculatedYAxisConfig = useMemo(() => {
    return {
      ...yAxisConfig,
      maxValue: yAxisConfig?.maxValue ?? niceValues.niceMax,
      minValue: niceValues.niceMin,
      step: yAxisConfig?.step ?? niceValues.tickSpacing,
      tick: {
        interval: yAxisInterval,
      },
    };
  }, [yAxisConfig, niceValues, yAxisInterval]);

  const calculatedXAxisConfig = useMemo(() => {
    return {
      ...xAxisConfig,
      labels: xAxisConfig?.labels || [],
    };
  }, [xAxisConfig]);

  const onChartLayout = useCallback(
    (event: LayoutChangeEvent) => {
      const { width, height } = event.nativeEvent.layout;

      if (width !== chartSize.width || height !== chartSize.height) {
        setChartSize({ width, height });
      }
    },
    [setChartSize, chartSize]
  );

  const renderContent = useCallback(
    ({ coordinates }: { coordinates: AxisCoordinates }) =>
      data.map((series) => (
        <Line
          color={colorScale(series.label)}
          testID={`line-${series.label}`}
          key={series.label}
          data={series.data}
          coordinates={coordinates}
          maxValue={calculatedYAxisConfig.maxValue || 0}
          labels={Array.from(
            { length: calculatedXAxisConfig.labels?.length || 0 },
            (_, i) => i.toString()
          )}
          minValue={calculatedYAxisConfig.minValue || 0}
        />
      )),
    [data, calculatedYAxisConfig, calculatedXAxisConfig, colorScale]
  );

  return (
    <StyledLineChartWrapper
      onLayout={onChartLayout}
      style={style}
      testID={testID}
    >
      <ChartFrame
        xAxisConfig={calculatedXAxisConfig}
        yAxisConfig={calculatedYAxisConfig}
        width={chartSize.width}
        height={chartSize.height}
        headerConfig={headerConfig}
        renderContent={renderContent}
        isEmpty={data.length === 0}
        emptyText={emptyText}
      />
    </StyledLineChartWrapper>
  );
};

export default LineChart;
