import React from 'react'

import { DecimalCount, scaledUnits } from '@baurine/grafana-value-formats'
import { Chart, Partition, Settings } from '@elastic/charts'
import {
  Box,
  Card,
  Flex,
  Group,
  Skeleton,
  Stack,
  Typography,
  useMantineTheme
} from '@tidbcloud/uikit'

import { useChartThemeConfig } from './_shared/chartTheme'
import { withAlpha } from './colors'
import {
  isTopSQLSystemInternalUserLabel,
  TOP_SQL_BACKEND_OTHERS_USER
} from './constants'
import { formatSharePercentage } from './formatters'

interface UserShareCardProps {
  loading?: boolean
  totalRU: number
  items: Array<{ key: string; label: string; ru: number }>
}

const DONUT_SIZE = 169
const DONUT_THICKNESS = 16
const DONUT_EMPTY_SIZE_RATIO = (DONUT_SIZE - DONUT_THICKNESS * 2) / DONUT_SIZE
const DONUT_COLOR_STEPS = [8, 6, 4, 2, 0] as const
const DONUT_COLOR_ALPHA = 0.8

function simpleCountUnit(symbol: string) {
  const units = ['', 'K', 'M', 'B', 'T']
  const scaler = scaledUnits(1000, units)

  return (
    size: number,
    decimals?: DecimalCount,
    scaledDecimals?: DecimalCount
  ) => {
    if (size === null) {
      return ''
    }

    const scaled = scaler(size, decimals, scaledDecimals)
    return `${scaled} ${symbol}`
  }
}

const formatRU = simpleCountUnit('RU')

const UserShareCard: React.FC<React.PropsWithChildren<UserShareCardProps>> = ({
  loading = false,
  totalRU,
  items
}) => {
  const { themeConfig } = useChartThemeConfig()
  const { colors } = useMantineTheme()
  const donutColors = DONUT_COLOR_STEPS.map((step) =>
    withAlpha(colors.navy[step], DONUT_COLOR_ALPHA)
  )
  const emptyColor = withAlpha(colors.carbon[2], DONUT_COLOR_ALPHA)
  const backendOthersItem = items.find(
    (item) =>
      item.key === TOP_SQL_BACKEND_OTHERS_USER ||
      item.label === TOP_SQL_BACKEND_OTHERS_USER
  )
  const namedItems = items.filter(
    (item) =>
      item.key !== TOP_SQL_BACKEND_OTHERS_USER &&
      item.label !== TOP_SQL_BACKEND_OTHERS_USER
  )
  const displayItems =
    backendOthersItem != null
      ? namedItems.length <= 3
        ? [
            ...namedItems,
            {
              key: 'others',
              label: 'Others',
              ru: backendOthersItem.ru
            }
          ]
        : [
            ...namedItems.slice(0, 3),
            {
              key: 'others',
              label: 'Others',
              ru:
                backendOthersItem.ru +
                namedItems.slice(3).reduce((sum, item) => sum + item.ru, 0)
            }
          ]
      : items.length <= 4
      ? items
      : [
          ...items.slice(0, 3),
          {
            key: 'others',
            label: 'Others',
            ru: items.slice(3).reduce((sum, item) => sum + item.ru, 0)
          }
        ]
  const colorMap = displayItems.reduce<Record<string, string>>(
    (map, item, index) => {
      map[item.key] = donutColors[index % donutColors.length]
      map[item.label] = donutColors[index % donutColors.length]
      return map
    },
    {}
  )
  const chartData = displayItems.some((item) => item.ru > 0)
    ? displayItems.filter((item) => item.ru > 0)
    : [{ key: 'empty', label: 'Empty', ru: 1 }]

  return (
    <Card withBorder p='md' h={280} data-testid='top-sql-user-share-card'>
      <Stack gap='lg' h='100%'>
        <Typography variant='title-md'>Top 3 DB Users (RU)</Typography>

        {loading ? (
          <Flex
            gap={18}
            wrap='nowrap'
            align='center'
            sx={{ flex: 1, minHeight: 0 }}
          >
            <Skeleton
              circle
              h={DONUT_SIZE}
              w={DONUT_SIZE}
              sx={{ flexShrink: 0 }}
            />
            <Stack
              gap='md'
              justify='center'
              sx={{ flex: 1, minWidth: 0, height: '100%' }}
            >
              <Skeleton h={20} w='60%' />
              <Skeleton h={20} w='75%' />
              <Skeleton h={20} w='70%' />
              <Skeleton h={20} w='55%' />
            </Stack>
          </Flex>
        ) : (
          <Flex
            gap={18}
            wrap='nowrap'
            align='center'
            sx={{ flex: 1, minHeight: 0 }}
          >
            <Box
              w={DONUT_SIZE}
              h={DONUT_SIZE}
              pos='relative'
              sx={{ flexShrink: 0 }}
              data-testid='top-sql-user-share-chart'
            >
              <Chart>
                <Settings
                  baseTheme={themeConfig}
                  showLegend={false}
                  theme={{
                    chartMargins: { top: 0, right: 0, bottom: 0, left: 0 },
                    partition: {
                      emptySizeRatio: DONUT_EMPTY_SIZE_RATIO,
                      outerSizeRatio: 1,
                      circlePadding: 0,
                      radialPadding: 0,
                      sectorLineWidth: 0,
                      fillLabel: {
                        textColor: 'transparent'
                      },
                      linkLabel: {
                        maxCount: 0
                      }
                    }
                  }}
                />
                <Partition
                  id='top-sql-user-share-donut'
                  data={chartData}
                  valueAccessor={(datum: { ru: number }) => datum.ru}
                  valueFormatter={(value) => formatRU(value, 2, 2)}
                  percentFormatter={formatSharePercentage}
                  layers={[
                    {
                      groupByRollup: (datum: { label: string }) => datum.label,
                      shape: {
                        fillColor: (node) =>
                          colorMap[String(node.dataName)] || emptyColor
                      }
                    }
                  ]}
                />
              </Chart>

              <Box
                pos='absolute'
                top={0}
                right={0}
                bottom={0}
                left={0}
                sx={{
                  display: 'flex',
                  alignItems: 'center',
                  justifyContent: 'center',
                  pointerEvents: 'none'
                }}
              >
                <Stack gap={0} align='center' sx={{ textAlign: 'center' }}>
                  <Typography variant='headline-lg'>
                    {formatRU(totalRU, 2, 2)}
                  </Typography>
                </Stack>
              </Box>
            </Box>

            <Stack
              gap='md'
              justify='center'
              sx={{ flex: 1, minWidth: 0, height: '100%' }}
              data-testid='top-sql-user-share-legend'
            >
              {displayItems.map((item) => {
                const share = totalRU > 0 ? (item.ru / totalRU) * 100 : 0

                return (
                  <Group
                    key={item.key}
                    gap='sm'
                    wrap='nowrap'
                    align='flex-start'
                  >
                    <Box
                      w={10}
                      h={10}
                      mt={6}
                      sx={{
                        borderRadius: 999,
                        backgroundColor: colorMap[item.key] || emptyColor,
                        flexShrink: 0
                      }}
                    />

                    <Stack gap={2}>
                      <Typography
                        variant='body-lg'
                        fs={
                          isTopSQLSystemInternalUserLabel(item.label)
                            ? 'italic'
                            : undefined
                        }
                      >
                        {item.label}
                      </Typography>
                      <Group gap={6} wrap='nowrap'>
                        <Typography variant='body-lg'>
                          {formatRU(item.ru, 2, 2)}
                        </Typography>
                        <Typography variant='label-md' c='carbon.7'>
                          {formatSharePercentage(share)}
                        </Typography>
                      </Group>
                    </Stack>
                  </Group>
                )
              })}
            </Stack>
          </Flex>
        )}
      </Stack>
    </Card>
  )
}

export default UserShareCard
