import {
  AnnotationDomainType,
  Axis,
  Chart,
  Fit,
  LineAnnotation,
  LineSeries,
  Position,
  ScaleType,
  Settings
} from '@elastic/charts'
import { useChartColors, useChartThemeConfig } from '@tidb-cloud-uikit/theme/Chart'
import { Box, Button, Card, Group, HoverCard, SimpleGrid, Stack, Typography } from '@tidbcloud/uikit'
import { useDisclosure } from '@tidbcloud/uikit/hooks'
import { ReactNode, useMemo, useRef, useState } from 'react'

import dayjs from 'dbaas/components/dayjs'
import { useTimeFormatter } from 'dbaas/components/TimeComponent'
import {
  Nextgenv1beta2ListRegionCapacitiesResponseRegionCapacity,
  V1beta2ByocVcpuPool
} from 'dbaas/services/api-clients/v2025/tidb-management/v1beta2/interface'
import useStores from 'dbaas/stores/useStores'

import { alignChartRange, getChartTimeFormat, getChartXAxisDomain, useChartHandle } from './charts'
import { useGetByocResourcePoolVcpuMetrics } from './useGetByocDataplaneMetricsSourceURL'
import { VCPULimitModal } from './VCPULimitModal'
import { VCPUManualScalingModal } from './VCPUManualScalingModal'

interface VCPUUsageChartCardProps {
  children: ReactNode
  capacity?: Nextgenv1beta2ListRegionCapacitiesResponseRegionCapacity
  chartsOnly?: boolean
  onUpdated?: () => void
  onRefetchPools?: () => void
  pool: V1beta2ByocVcpuPool
  regionId?: string
  startUnix: number
  endUnix: number
  refreshKey?: number
}

interface PoolUsageChartProps {
  children: ReactNode
  capacity?: Nextgenv1beta2ListRegionCapacitiesResponseRegionCapacity
  chartsOnly?: boolean
  onUpdated?: () => void
  startUnix: number
  endUnix: number
  orgId: string
  projectId: string
  pool: V1beta2ByocVcpuPool
  regionId?: string
  onRefetchPools?: () => void
  useCapacityFallback?: boolean
  refreshKey?: number
}

const MODIFYING_POOL_ACTION_DISABLED_MESSAGE =
  'The current resource pool is being modified. Please try again in a few minutes.'

const getPoolDisplayName = (pool: V1beta2ByocVcpuPool) => {
  if (pool.name) return pool.name
  if (pool.isDefault) return 'Default Pool'

  return 'Pool'
}

const PoolUsageChart = ({
  children,
  capacity,
  chartsOnly = false,
  onUpdated,
  startUnix,
  endUnix,
  orgId,
  projectId,
  pool,
  regionId,
  onRefetchPools,
  useCapacityFallback = false,
  refreshKey
}: PoolUsageChartProps) => {
  const { themeConfig } = useChartThemeConfig()
  const { chartColors, themeColors } = useChartColors()
  const requestedRange = useMemo<[number, number]>(() => [startUnix, endUnix], [endUnix, startUnix])
  const [limitOpened, limitHandlers] = useDisclosure(false)
  const [manualScalingOpened, setManualScalingOpened] = useState(false)
  const chartContainerRef = useRef<HTMLDivElement>(null)
  const [chartHandle] = useChartHandle(chartContainerRef)
  const queryStep = chartHandle.calcIntervalSec(requestedRange)
  const [queryStartUnix, queryEndUnix] = alignChartRange(requestedRange, queryStep)
  const selectedRange = useMemo<[number, number]>(() => [queryStartUnix, queryEndUnix], [queryEndUnix, queryStartUnix])
  const xAxisFormatter = useTimeFormatter(getChartTimeFormat(selectedRange))
  const {
    data: o11yVcpuSeries = [],
    isLoading: isVcpuMetricsLoading,
    isFetching: isVcpuMetricsFetching,
    refetch: refetchVcpuMetrics
  } = useGetByocResourcePoolVcpuMetrics({
    orgId,
    projectId,
    regionId: regionId ?? capacity?.region?.regionId,
    dataplaneId: pool.dataplaneId,
    resourcePoolId: pool.resourcePoolId,
    startUnix: queryStartUnix,
    endUnix: queryEndUnix,
    step: queryStep,
    refreshKey
  })

  const capacityUsageSeries = useMemo(() => {
    return (
      capacity?.historyUsages
        ?.map((usage) => {
          if (!usage.metricsTime) return null
          return [dayjs(usage.metricsTime).valueOf(), Number(usage.usedVcpus || 0)]
        })
        .filter((item): item is [number, number] => !!item)
        .sort((a, b) => a[0] - b[0]) ?? []
    )
  }, [capacity?.historyUsages])
  const usageSeries = useMemo(() => {
    const source = o11yVcpuSeries.length > 0 ? o11yVcpuSeries : useCapacityFallback ? capacityUsageSeries : []

    return source.filter(([timestamp]) => timestamp >= queryStartUnix * 1000 && timestamp <= queryEndUnix * 1000)
  }, [capacityUsageSeries, o11yVcpuSeries, queryEndUnix, queryStartUnix, useCapacityFallback])
  const currentVcpu = usageSeries[usageSeries.length - 1]?.[1] ?? Number(pool.vcpusUsed || 0)
  const currentVcpuDisplay = currentVcpu > 0 ? currentVcpu : '-'
  const vcpuLimit = Number(pool.vcpusLimit ?? capacity?.totalVcpusLimit ?? 0)
  const hasVcpuLimit = vcpuLimit > 0
  const yAxisMax = useMemo(() => {
    const maxUsage = Math.max(...usageSeries.map(([, value]) => value), 0)
    const maxValue = Math.max(maxUsage, vcpuLimit, 1)

    return hasVcpuLimit && maxValue === vcpuLimit ? vcpuLimit * 1.05 : maxValue
  }, [hasVcpuLimit, usageSeries, vcpuLimit])
  const hasUsageData = usageSeries.length > 0
  const isLoadingUsageData = isVcpuMetricsLoading || isVcpuMetricsFetching
  const shouldShowPoint = usageSeries.length === 1
  const displaySeries = useMemo<[number, number | null][]>(() => {
    if (hasUsageData) {
      return [[queryStartUnix * 1000, null], ...usageSeries, [queryEndUnix * 1000, null]]
    }
    return [
      [queryStartUnix * 1000, null],
      [queryEndUnix * 1000, null]
    ]
  }, [hasUsageData, queryEndUnix, queryStartUnix, usageSeries])
  const xDomain = useMemo(() => getChartXAxisDomain(selectedRange), [selectedRange])
  const poolName = getPoolDisplayName(pool)
  const isPoolModifying = pool.state === 'MODIFYING'
  const renderModifyingPoolAction = (action: ReactNode) => {
    if (!isPoolModifying) {
      return action
    }

    return (
      <HoverCard width={320}>
        <HoverCard.Target>
          <Box component="span" display="inline-block">
            {action}
          </Box>
        </HoverCard.Target>
        <HoverCard.Dropdown>
          <Typography variant="body-md">{MODIFYING_POOL_ACTION_DISABLED_MESSAGE}</Typography>
        </HoverCard.Dropdown>
      </HoverCard>
    )
  }

  const usageChart = (
    <Card withBorder p="xl" bg="carbon.1" data-testid="vcpu-management-usage-chart-card">
      <Stack gap="xl">
        <Group justify="space-between" gap="md" pr={24}>
          <Typography variant="label-md">vCPU Usage Trend</Typography>
          <Group>
            <Typography variant="label-lg" c="carbon.7" inline>
              Current vCPU:{' '}
              <Typography variant="title-lg" fz={16} c="carbon.7" component="span">
                {currentVcpuDisplay}
              </Typography>
            </Typography>

            {hasVcpuLimit && (
              <Typography variant="label-lg" c="carbon.7" inline>
                Pool vCPU Limit:{' '}
                <Typography variant="title-lg" fz={16} c="carbon.7" component="span">
                  {vcpuLimit}
                </Typography>
              </Typography>
            )}
          </Group>
        </Group>

        <Box
          ref={chartContainerRef}
          sx={{
            position: 'relative',
            '.echAnnotation__marker': {
              background: 'transparent !important',
              boxShadow: 'none !important',
              border: 'none !important',
              padding: '0 !important',
              marginLeft: 3
            },
            '.echAnnotation__icon': {
              background: 'transparent !important',
              padding: '0 !important'
            }
          }}
          h={160}
        >
          <Chart>
            <Settings
              baseTheme={{
                ...themeConfig,
                chartPaddings: {
                  ...themeConfig.chartPaddings,
                  right: 36
                }
              }}
              xDomain={xDomain}
            />
            <Axis id="x" position={Position.Bottom} ticks={7} tickFormat={(value) => xAxisFormatter(value / 1000)} />
            <Axis id="y" position={Position.Left} ticks={5} domain={{ min: 0, max: yAxisMax }} />
            {hasVcpuLimit && (
              <LineAnnotation
                id={`${pool.resourcePoolId || poolName}-limit`}
                domainType={AnnotationDomainType.YDomain}
                dataValues={[{ dataValue: vcpuLimit }]}
                hideTooltips
                marker={
                  <Typography variant="body-sm" c="carbon.7">
                    Limit
                  </Typography>
                }
                markerPosition={Position.Right}
                style={{ line: { dash: [4, 4], strokeWidth: 1, stroke: themeColors.red[7] } }}
              />
            )}
            <LineSeries
              id="Current vCPU"
              xScaleType={ScaleType.Time}
              yScaleType={ScaleType.LinearBinary}
              xAccessor={0}
              yAccessors={[1]}
              data={displaySeries}
              fit={Fit.Carry}
              lineSeriesStyle={
                hasUsageData
                  ? { line: { strokeWidth: 2, stroke: chartColors.blue[8] } }
                  : { line: { strokeWidth: 0, opacity: 0 } }
              }
              pointStyleAccessor={() => ({
                radius: shouldShowPoint ? 4 : 0,
                visible: shouldShowPoint
              })}
            />
          </Chart>
          {!isLoadingUsageData && !hasUsageData && (
            <Stack
              align="center"
              gap={4}
              justify="center"
              sx={{
                position: 'absolute',
                left: '50%',
                top: '50%',
                transform: 'translate(-50%, -50%)',
                pointerEvents: 'none',
                zIndex: 1
              }}
            >
              <Typography variant="title-md" c="carbon.7">
                No Data Available Yet
              </Typography>
              <Typography variant="label-md" c="carbon.7">
                Data will appear when cluster available
              </Typography>
            </Stack>
          )}
        </Box>
      </Stack>
    </Card>
  )

  return (
    <>
      {chartsOnly ? (
        <Stack gap="md">
          {usageChart}
          {children}
        </Stack>
      ) : (
        <Card withBorder p="md" data-testid="vcpu-management-pool-card" data-resource-pool-id={pool.resourcePoolId}>
          <Stack gap="md">
            <Group justify="space-between" align="center">
              <Typography variant="title-md">{poolName}</Typography>
              <Group gap="sm">
                {renderModifyingPoolAction(
                  <Button size="sm" variant="default" onClick={limitHandlers.open} disabled={isPoolModifying}>
                    Update vCPU Limit
                  </Button>
                )}
                {renderModifyingPoolAction(
                  <Button
                    size="sm"
                    variant="default"
                    onClick={() => setManualScalingOpened(true)}
                    disabled={isPoolModifying}
                  >
                    Basic Capacity Settings
                  </Button>
                )}
              </Group>
            </Group>
            <SimpleGrid cols={2} spacing="md">
              {usageChart}
              {children}
            </SimpleGrid>
          </Stack>
        </Card>
      )}
      {!chartsOnly && (
        <>
          <VCPULimitModal
            opened={limitOpened}
            onClose={limitHandlers.close}
            orgId={orgId}
            poolName={poolName}
            projectId={projectId}
            resourcePoolId={pool.resourcePoolId}
            currentLimit={pool.vcpusLimit ?? capacity?.totalVcpusLimit}
            onSuccess={() => {
              onRefetchPools?.()
              refetchVcpuMetrics()
              onUpdated?.()
            }}
          />
          <VCPUManualScalingModal
            opened={manualScalingOpened}
            onClose={() => setManualScalingOpened(false)}
            orgId={orgId}
            poolName={poolName}
            projectId={projectId}
            resourcePoolId={pool.resourcePoolId}
            onResetLimit={() => {
              setManualScalingOpened(false)
              limitHandlers.open()
            }}
            onSuccess={() => {
              onRefetchPools?.()
              refetchVcpuMetrics()
              onUpdated?.()
            }}
          />
        </>
      )}
    </>
  )
}

export const VCPUUsageChartCard = ({
  children,
  capacity,
  chartsOnly,
  onUpdated,
  onRefetchPools,
  pool,
  regionId,
  startUnix,
  endUnix,
  refreshKey
}: VCPUUsageChartCardProps) => {
  const {
    store: {
      lastVisitLocation: { orgId, projectId }
    }
  } = useStores()

  return (
    <PoolUsageChart
      children={children}
      capacity={capacity}
      chartsOnly={chartsOnly}
      onUpdated={onUpdated}
      startUnix={startUnix}
      endUnix={endUnix}
      orgId={orgId}
      projectId={projectId}
      pool={pool}
      regionId={regionId}
      onRefetchPools={onRefetchPools}
      useCapacityFallback={pool.isDefault}
      refreshKey={refreshKey}
    />
  )
}
