import { AreaSeries, Axis, Chart, LineSeries, Position, Settings } from '@elastic/charts'
import { useChartColors, useChartThemeConfig } from '@tidb-cloud-uikit/theme/Chart'
import { Box, Typography, useMantineTheme } from '@tidbcloud/uikit'
import { groupBy, keyBy } from 'lodash-es'
import { observer } from 'mobx-react'
import React, { useMemo } from 'react'

import { LineFormData } from '../FormConfig/LineFormData'
import { AggregationEnum, AppearanceEnum, ChartData, ColumnLevelEnum, ContainerSize } from '../type'
import { getColumnAccessor, processChartData } from '../util'

export const LineChart: React.FC<
  React.PropsWithChildren<{
    data: ChartData | null
    formData: LineFormData
    title: string
    containerSize?: ContainerSize
  }>
> = observer(({ data, formData, title, containerSize }) => {
  const { chartColorsOpacity08 } = useChartColors()
  const { themeConfig } = useChartThemeConfig()
  const { colors } = useMantineTheme()
  const xAxisField = formData.columnData[ColumnLevelEnum.First]?.value[0]?.field || ''
  const lineValue = formData.columnData[ColumnLevelEnum.Second]?.value || []

  const yAxisAccessors =
    lineValue?.map((v) => getColumnAccessor(v.aggregation || AggregationEnum.None, v.field || '')) || []

  const seriesName =
    lineValue?.map((v) => ({
      accessor: getColumnAccessor(v.aggregation || AggregationEnum.None, v.field || ''),
      name: v.field
    })) || []

  const seriesData = useMemo(() => {
    return processChartData(data, xAxisField, lineValue)
  }, [data, xAxisField, yAxisAccessors])

  const seriesValue = formData.columnData[ColumnLevelEnum.Third]?.value
  const groupedData = groupBy(seriesData, (v) => {
    return v[seriesValue?.[0]?.field || '']
  })

  const appearanceRecord = useMemo(() => {
    return keyBy(formData.appearance, 'key')
  }, [formData.appearance])

  const xAxisTitle = appearanceRecord[AppearanceEnum.LabelXAxis].value.toString()

  const yAxisTitle = appearanceRecord[AppearanceEnum.LabelYAxis].value.toString()

  const yAxisCrop = !!appearanceRecord[AppearanceEnum.CropYAxis].value

  const showLegend = !!appearanceRecord[AppearanceEnum.ShowLegend].value

  const chartSeries = () => {
    const isFillArea = appearanceRecord[AppearanceEnum.FillArea].value
    if (seriesValue?.length || 0 > 0) {
      return Object.entries(groupedData)
        .filter(([key]) => key !== '')
        .map(([key, value], index) => {
          const config = {
            id: key,
            key,
            xAccessor: xAxisField,
            yAccessors: yAxisAccessors,
            data: value,
            color: chartColorsOpacity08[index % chartColorsOpacity08.length]
          }
          return isFillArea ? <AreaSeries {...config} /> : <LineSeries {...config} />
        })
    } else {
      return isFillArea ? (
        <AreaSeries
          id="series1"
          name={{ names: seriesName }}
          xAccessor={xAxisField}
          yAccessors={yAxisAccessors}
          data={seriesData}
          color={chartColorsOpacity08}
        />
      ) : (
        <LineSeries
          id="series1"
          name={{ names: seriesName }}
          xAccessor={xAxisField}
          yAccessors={yAxisAccessors}
          data={seriesData}
          color={chartColorsOpacity08}
        />
      )
    }
  }

  return data ? (
    <Box h="100%" pb={32}>
      <Box
        pt="xs"
        pl="md"
        sx={(theme) => ({
          color: theme.colors.carbon[8]
        })}
      >
        <Typography variant="body-lg">{title}</Typography>
      </Box>
      <Chart>
        <Settings
          showLegend={showLegend}
          legendPosition={Position.Top}
          legendSize={35}
          theme={{
            ...themeConfig,
            lineSeriesStyle: {
              line: { strokeWidth: 2 },
              point: {
                fill: colors.carbon[0],
                visible: !!appearanceRecord[AppearanceEnum.ShowPoints].value
              }
            },
            areaSeriesStyle: {
              line: { strokeWidth: 2 },
              point: {
                visible: !!appearanceRecord[AppearanceEnum.ShowPoints].value
              }
            },
            legend: { verticalWidth: 80, horizontalHeight: 80 }
          }}
        />
        <Axis
          id={'xAxis'}
          title={xAxisTitle}
          position={Position.Bottom}
          style={{
            tickLabel: { rotation: (containerSize?.height || 0) > 500 ? -45 : 0, padding: 10 }
          }}
        />
        <Axis
          id={'yAxis'}
          title={yAxisTitle}
          position={Position.Left}
          domain={{
            min: NaN,
            max: NaN,
            fit: yAxisCrop
          }}
          style={{ tickLabel: { padding: 10 } }}
        />
        {chartSeries()}
      </Chart>
    </Box>
  ) : null
})
