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

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

export const BarChart: React.FC<
  React.PropsWithChildren<{
    data: ChartData | null
    formData: BarFormData
    title: string
    containerSize?: ContainerSize
  }>
> = observer(({ data, formData, title, containerSize }) => {
  const { chartColorsOpacity08 } = useChartColors()
  const { themeConfig } = useChartThemeConfig()
  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 appearanceRecord = useMemo(() => {
    return keyBy(formData.appearance, 'key')
  }, [formData.appearance])

  const seriesData = useMemo(() => {
    return processChartData(
      data,
      xAxisField,
      lineValue,
      appearanceRecord[AppearanceEnum.OrderDirection].value.toString() as OrderTypeEnum
    )
  }, [data, xAxisField, yAxisAccessors, formData])

  const seriesValue = formData.columnData[ColumnLevelEnum.Third]?.value

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

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

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

  const orientation = appearanceRecord[AppearanceEnum.Orientation].value.toString()

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

  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}
          rotation={orientation === 'Horizontal' ? 90 : 0}
          theme={{
            ...themeConfig,
            legend: { verticalWidth: 80, horizontalHeight: 80 }
          }}
        />
        <Axis
          id={'xAxis'}
          title={xAxisTitle}
          position={Position.Bottom}
          style={{
            tickLabel: { rotation: (containerSize?.height || 0) > 500 ? -45 : 0 },
            tickLine: { size: 1, padding: 10 }
          }}
        />
        <Axis id={'yAxis'} title={yAxisTitle} position={Position.Left} style={{ tickLine: { size: 1, padding: 10 } }} />
        {seriesValue?.length || 0 > 0 ? (
          Object.entries(groupedData)
            .filter(([key]) => key !== '')
            .map(([key, value], index) => (
              <BarSeries
                id={key}
                key={key}
                xAccessor={xAxisField}
                yAccessors={yAxisAccessors}
                data={value}
                color={chartColorsOpacity08[index % chartColorsOpacity08.length]}
              />
            ))
        ) : (
          <BarSeries
            id="series1"
            name={{ names: seriesName }}
            xAccessor={xAxisField}
            yAccessors={yAxisAccessors}
            data={seriesData}
            color={chartColorsOpacity08}
          />
        )}
      </Chart>
    </Box>
  ) : null
})
