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

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) => datum.ru}
                  valueFormatter={(value) => formatRU(value, 2, 2)}
                  percentFormatter={formatSharePercentage}
                  layers={[
                    {
                      groupByRollup: (datum) => 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
