import React from 'react'
import { useEffect, useMemo, useState } from 'react'

import { getValueFormat } from '@baurine/grafana-value-formats'
import {
  Axis,
  Chart,
  LineSeries,
  Position,
  ScaleType,
  Settings,
  TooltipStickTo,
  TooltipType
} from '@elastic/charts'
import {
  ActionIcon,
  Badge,
  Box,
  Card,
  CopyButton,
  Flex,
  Loader,
  Progress,
  SimpleGrid,
  Stack,
  Table,
  Typography
} from '@tidbcloud/uikit'
import { CodeBlock } from '@tidbcloud/uikit/biz'
import {
  IconCheck,
  IconChevronDown,
  IconChevronLeft,
  IconChevronRight,
  IconCopy01
} from '@tidbcloud/uikit/icons'

import { useChartColors, useChartThemeConfig } from './_shared/chartTheme'
import { DetailsDrawer } from './_shared/DetailsDrawer'
import { formatSql } from './_shared/HighlightSQL'
import { eventTracking } from './_shared/tracking'
import { useTimeFormatter } from './_shared/useTimeFormatter'
import { TOP_SQL_OTHERS_LABEL } from './display'
import { formatSharePercentage } from './formatters'
import { useTopSQLTooltipTimeHeaderFormatter } from './time'
import {
  TopSQLExecutionPlanAnalysisPlan,
  TopSQLExecutionPlanAnalysisResponse
} from './types'

function ellipsisText(value: string, headLength = 10, tailLength = 4) {
  if (!value || value.length <= headLength + tailLength + 3) {
    return value
  }

  return `${value.slice(0, headLength)}...${value.slice(-tailLength)}`
}

function DigestWithCopy({
  value,
  shorten = false,
  fw,
  showCopy = true,
  headLength = 10,
  tailLength = 4
}: {
  value: string
  shorten?: boolean
  fw?: number
  showCopy?: boolean
  headLength?: number
  tailLength?: number
}) {
  const displayValue = shorten
    ? ellipsisText(value, headLength, tailLength)
    : value

  return (
    <Flex
      align='center'
      gap={6}
      wrap='nowrap'
      sx={{ minWidth: 0, width: '100%' }}
    >
      <Typography
        variant='body-lg'
        fw={fw}
        title={value}
        sx={{ flex: 1, minWidth: 0, whiteSpace: 'nowrap', overflow: 'hidden' }}
      >
        {displayValue}
      </Typography>
      {showCopy && (
        <CopyButton value={value} timeout={1500}>
          {({ copied, copy }) => (
            <ActionIcon
              variant='subtle'
              size={18}
              onClick={copy}
              aria-label='Copy value'
              sx={{ flexShrink: 0 }}
            >
              {copied ? <IconCheck size={14} /> : <IconCopy01 size={14} />}
            </ActionIcon>
          )}
        </CopyButton>
      )}
    </Flex>
  )
}

function SummaryCard({
  label,
  labelAction,
  children
}: {
  label: string
  labelAction?: React.ReactNode
  children: React.ReactNode
}) {
  return (
    <Card
      withBorder
      bg='carbon.0'
      py={12}
      px={16}
      data-testid='top-sql-analysis-summary-card'
    >
      <Stack gap={6}>
        <Flex align='center' justify='space-between' gap='xs'>
          <Typography variant='label-md' c='carbon.7'>
            {label}
          </Typography>
          {labelAction}
        </Flex>
        <Box
          sx={{
            fontWeight: 700,
            minWidth: 0,
            overflow: 'hidden',
            '& *': { fontWeight: 'inherit' }
          }}
        >
          {children}
        </Box>
      </Stack>
    </Card>
  )
}

function PlanTrendChart({
  plans,
  timeRangeValue
}: {
  plans: TopSQLExecutionPlanAnalysisPlan[]
  timeRangeValue: [number, number]
}) {
  const { themeConfig } = useChartThemeConfig()
  const { chartColorsOpaque } = useChartColors()
  const sameDay = useMemo(() => {
    const dayFormatter = new Intl.DateTimeFormat('en-US', {
      year: 'numeric',
      month: '2-digit',
      day: '2-digit'
    })

    return (
      dayFormatter.format(timeRangeValue[0] * 1000) ===
      dayFormatter.format(timeRangeValue[1] * 1000)
    )
  }, [timeRangeValue])
  const xAxisFormatter = useTimeFormatter(sameDay ? 'HH:mm' : 'MM-DD HH:mm')
  const tooltipTimeHeaderFormatter = useTopSQLTooltipTimeHeaderFormatter()

  const seriesData = useMemo(
    () =>
      plans.map((plan, index) => ({
        id: plan.key,
        name: ellipsisText(plan.planDigest, 8, 4),
        color: chartColorsOpaque[index % chartColorsOpaque.length],
        data: plan.trend.map((point) => ({
          timestamp: point.timestamp * 1000,
          value: point.value
        }))
      })),
    [chartColorsOpaque, plans]
  )

  return (
    <Box h={120} data-testid='top-sql-analysis-trend-chart'>
      <Chart>
        <Settings
          baseTheme={themeConfig}
          showLegend={false}
          xDomain={{
            min: timeRangeValue[0] * 1000,
            max: timeRangeValue[1] * 1000
          }}
          tooltip={{
            type: TooltipType.Crosshairs,
            headerFormatter: ({ value }) =>
              tooltipTimeHeaderFormatter(value / 1000),
            stickTo: TooltipStickTo.MousePosition
          }}
        />
        <Axis
          id='trend-left'
          position={Position.Left}
          ticks={4}
          tickFormat={(value) => getValueFormat('short')(value, 0)}
        />
        <Axis
          id='trend-bottom'
          position={Position.Bottom}
          tickFormat={(value) => xAxisFormatter(value / 1000)}
        />
        {seriesData.map((series) => (
          <LineSeries
            key={series.id}
            id={series.id}
            name={series.name}
            color={series.color}
            xScaleType={ScaleType.Time}
            yScaleType={ScaleType.Linear}
            xAccessor='timestamp'
            yAccessors={['value']}
            data={series.data}
            lineSeriesStyle={{
              point: {
                visible: false
              }
            }}
          />
        ))}
      </Chart>
    </Box>
  )
}

function PlanRow({
  plan,
  isExpanded,
  onToggle,
  timeRangeValue
}: {
  plan: TopSQLExecutionPlanAnalysisPlan
  isExpanded: boolean
  onToggle: () => void
  timeRangeValue: [number, number]
}) {
  return (
    <>
      <Table.Tr data-testid='top-sql-analysis-plan-row'>
        <Table.Td>
          <ActionIcon
            variant='subtle'
            size={20}
            onClick={onToggle}
            aria-label='Toggle plan detail'
          >
            {isExpanded ? (
              <IconChevronDown size={14} />
            ) : (
              <IconChevronRight size={14} />
            )}
          </ActionIcon>
        </Table.Td>
        <Table.Td w={170} miw={170}>
          <DigestWithCopy value={plan.planDigest} shorten />
        </Table.Td>
        <Table.Td>
          <Typography variant='body-lg'>
            {getValueFormat('short')(plan.ru, 2, 2)}
          </Typography>
        </Table.Td>
        <Table.Td>
          <Typography variant='body-lg'>
            {getValueFormat('short')(plan.meanRU, 2, 2)}
          </Typography>
        </Table.Td>
        <Table.Td>
          <Typography variant='body-lg'>
            {formatSharePercentage(plan.share)}
          </Typography>
        </Table.Td>
        <Table.Td>
          <Typography variant='body-lg'>
            {getValueFormat('short')(plan.executions, 0, 1)}
          </Typography>
        </Table.Td>
        <Table.Td>
          <Typography variant='body-lg'>
            {getValueFormat('ns')(plan.totalLatencyNs, 1)}
          </Typography>
        </Table.Td>
        <Table.Td>
          <Typography variant='body-lg'>
            {getValueFormat('ns')(plan.meanLatencyNs, 1)}
          </Typography>
        </Table.Td>
      </Table.Tr>
      {isExpanded && (
        <Table.Tr>
          <Table.Td colSpan={8} p='md'>
            <Stack gap='lg'>
              <Card withBorder p='md'>
                <Stack gap='xs'>
                  <Typography variant='label-md' fw={500}>
                    RU Trend
                  </Typography>
                  <PlanTrendChart
                    plans={[plan]}
                    timeRangeValue={timeRangeValue}
                  />
                </Stack>
              </Card>

              {plan.planText.trim() && (
                <Card withBorder p='md' sx={{ minWidth: 0 }}>
                  <Stack gap='xs' sx={{ minWidth: 0 }}>
                    <Typography variant='label-md' fw={500}>
                      Query Execution Plan
                    </Typography>
                    <Box
                      sx={(theme) => ({
                        minWidth: 0,
                        width: '100%',
                        maxHeight: 480,
                        overflow: 'auto',
                        backgroundColor: theme.colors.carbon[0],
                        borderRadius: theme.radius.sm,
                        border: `1px solid ${theme.colors.carbon[3]}`
                      })}
                    >
                      <Box
                        component='pre'
                        sx={(theme) => ({
                          margin: 0,
                          padding: theme.spacing.sm,
                          whiteSpace: 'pre',
                          fontFamily: theme.fontFamilyMonospace,
                          fontSize: 12,
                          lineHeight: 1.5,
                          tabSize: 4
                        })}
                      >
                        {plan.planText}
                      </Box>
                    </Box>
                  </Stack>
                </Card>
              )}
            </Stack>
          </Table.Td>
        </Table.Tr>
      )}
    </>
  )
}

interface SQLExecutionPlanDrawerProps {
  opened: boolean
  loading?: boolean
  plansLoading?: boolean
  data?: TopSQLExecutionPlanAnalysisResponse
  timeRangeValue: [number, number]
  currentIndex?: number
  totalCount?: number
  onPrev?: () => void
  onNext?: () => void
  onClose: () => void
}

const SQLExecutionPlanDrawer: React.FC<
  React.PropsWithChildren<SQLExecutionPlanDrawerProps>
> = ({
  opened,
  loading,
  plansLoading,
  data,
  timeRangeValue,
  currentIndex = 0,
  totalCount = 0,
  onPrev,
  onNext,
  onClose
}) => {
  const [expandedPlanKey, setExpandedPlanKey] = useState<string>()
  const formattedStatementTemplate = useMemo(
    () => formatSql(data?.statementTemplate),
    [data?.statementTemplate]
  )

  useEffect(() => {
    if (!data?.plans.length) {
      setExpandedPlanKey(undefined)
      return
    }

    setExpandedPlanKey(data.plans[0].key)
  }, [data])

  return (
    <DetailsDrawer
      opened={opened}
      onClose={onClose}
      title={
        <Flex align='center' gap='sm' wrap='wrap'>
          <Typography variant='title-lg'>
            SQL Execution Plan Analysis
          </Typography>
          {data && (
            <Badge variant='outline' color='gray' size='lg'>
              #{data.rank}
            </Badge>
          )}
        </Flex>
      }
      size={960}
      data-testid='top-sql-analysis-drawer'
    >
      <DetailsDrawer.Body>
        {loading ? (
          <Stack align='center' justify='center' h='100%' py='md'>
            <Loader />
          </Stack>
        ) : !data ? (
          <Typography variant='body-lg' c='carbon.7' px='md' py='md'>
            No analysis data available.
          </Typography>
        ) : (
          <Stack gap='md'>
            <Stack gap='sm'>
              <Typography variant='title-md' fw={700}>
                Statement template
              </Typography>
              {data.isOthers ? (
                <Typography variant='body-lg' fs='italic' c='carbon.7'>
                  {TOP_SQL_OTHERS_LABEL}
                </Typography>
              ) : (
                <CodeBlock
                  language='sql'
                  foldProps={{ iconVisible: true, defaultHeight: 120 }}
                >
                  {formattedStatementTemplate}
                </CodeBlock>
              )}
            </Stack>

            <Stack gap='sm'>
              <Typography variant='title-md' fw={700}>
                Execution Summary
              </Typography>
              <SimpleGrid cols={{ base: 2, md: 4 }} spacing='md'>
                <SummaryCard
                  label='SQL Digest'
                  labelAction={
                    !data.isOthers && data.sqlDigest ? (
                      <CopyButton value={data.sqlDigest} timeout={1500}>
                        {({ copied, copy }) => (
                          <ActionIcon
                            variant='subtle'
                            size={18}
                            onClick={() => {
                              eventTracking(
                                'Top RU Detail Copy SQL Digest Clicked',
                                { sqlDigest: data.sqlDigest }
                              )
                              copy()
                            }}
                            aria-label='Copy SQL digest'
                          >
                            {copied ? (
                              <IconCheck size={14} />
                            ) : (
                              <IconCopy01 size={14} />
                            )}
                          </ActionIcon>
                        )}
                      </CopyButton>
                    ) : undefined
                  }
                >
                  {data.isOthers ? (
                    <Typography
                      variant='body-lg'
                      fw={700}
                      fs='italic'
                      c='carbon.7'
                    >
                      {TOP_SQL_OTHERS_LABEL}
                    </Typography>
                  ) : (
                    <DigestWithCopy
                      value={data.sqlDigest}
                      shorten
                      fw={700}
                      showCopy={false}
                      headLength={12}
                      tailLength={6}
                    />
                  )}
                </SummaryCard>
                <SummaryCard label='RU'>
                  <Typography variant='body-lg' fw={700}>
                    {getValueFormat('short')(data.ru, 2, 2)}
                  </Typography>
                </SummaryCard>
                <SummaryCard label='Mean RU'>
                  <Typography variant='body-lg' fw={700}>
                    {getValueFormat('short')(data.meanRU, 2, 2)}
                  </Typography>
                </SummaryCard>
                <SummaryCard label='Share'>
                  <Flex align='center' gap='sm'>
                    <Typography variant='body-lg' fw={700}>
                      {formatSharePercentage(data.share)}
                    </Typography>
                    <Progress
                      value={data.share}
                      size={8}
                      color='peacock.8'
                      sx={{ flex: 1, minWidth: 0 }}
                      styles={{ root: { backgroundColor: '#DCE3E5' } }}
                    />
                  </Flex>
                </SummaryCard>
                <SummaryCard label='Plan Counts'>
                  {plansLoading ? (
                    <Loader
                      size='sm'
                      data-testid='top-sql-analysis-plan-count-loading'
                    />
                  ) : (
                    <Typography variant='body-lg' fw={700}>
                      {data.planCount}
                    </Typography>
                  )}
                </SummaryCard>
                <SummaryCard label='Executions'>
                  <Typography variant='body-lg' fw={700}>
                    {getValueFormat('short')(data.executions, 0, 1)}
                  </Typography>
                </SummaryCard>
                <SummaryCard label='Total Latency'>
                  <Typography variant='body-lg' fw={700}>
                    {getValueFormat('ns')(data.totalLatencyNs, 1)}
                  </Typography>
                </SummaryCard>
                <SummaryCard label='Mean Latency'>
                  <Typography variant='body-lg' fw={700}>
                    {getValueFormat('ns')(data.meanLatencyNs, 1)}
                  </Typography>
                </SummaryCard>
              </SimpleGrid>
            </Stack>

            {!data.isOthers && (
              <Stack gap='sm' data-testid='top-sql-analysis-plans-section'>
                <Typography variant='title-md' fw={700}>
                  Execution Plans{plansLoading ? '' : ` (${data.planCount})`}
                </Typography>
                {plansLoading ? (
                  <Card
                    withBorder
                    p='lg'
                    data-testid='top-sql-analysis-plans-loading'
                  >
                    <Flex align='center' justify='center' gap='sm'>
                      <Loader size='sm' />
                      <Typography variant='body-lg' c='carbon.7'>
                        Loading execution plans...
                      </Typography>
                    </Flex>
                  </Card>
                ) : data.plans.length > 0 ? (
                  <Card withBorder p={0} sx={{ minWidth: 0 }}>
                    <Table
                      highlightOnHover
                      horizontalSpacing={8}
                      verticalSpacing={8}
                      style={{ tableLayout: 'fixed', width: '100%' }}
                    >
                      <Table.Thead>
                        <Table.Tr c='#6F787B'>
                          <Table.Th w={40}></Table.Th>
                          <Table.Th w={170} fw={500}>
                            Plan digest
                          </Table.Th>
                          <Table.Th fw={500}>Total RU</Table.Th>
                          <Table.Th fw={500}>Mean RU</Table.Th>
                          <Table.Th fw={500}>Share</Table.Th>
                          <Table.Th fw={500}>Executions</Table.Th>
                          <Table.Th fw={500}>Total Latency</Table.Th>
                          <Table.Th fw={500}>Mean Latency</Table.Th>
                        </Table.Tr>
                      </Table.Thead>
                      <Table.Tbody>
                        {data.plans.map((plan) => (
                          <PlanRow
                            key={plan.key}
                            plan={plan}
                            isExpanded={expandedPlanKey === plan.key}
                            onToggle={() => {
                              eventTracking(
                                'Top RU Detail Plan Expand Clicked',
                                {
                                  planDigest: plan.planDigest,
                                  expanded: expandedPlanKey !== plan.key
                                }
                              )
                              setExpandedPlanKey(
                                expandedPlanKey === plan.key
                                  ? undefined
                                  : plan.key
                              )
                            }}
                            timeRangeValue={timeRangeValue}
                          />
                        ))}
                      </Table.Tbody>
                    </Table>
                  </Card>
                ) : (
                  <Card
                    withBorder
                    p='lg'
                    data-testid='top-sql-analysis-plans-empty'
                  >
                    <Typography variant='body-lg' c='carbon.7' ta='center'>
                      No execution plans found for this SQL statement.
                    </Typography>
                  </Card>
                )}
              </Stack>
            )}
          </Stack>
        )}
      </DetailsDrawer.Body>
      <DetailsDrawer.Footer justify='flex-start'>
        <Flex align='center' gap='md'>
          <ActionIcon
            variant='default'
            size={40}
            onClick={onPrev}
            disabled={!opened || currentIndex <= 0}
            aria-label='Previous SQL'
          >
            <IconChevronLeft size={18} />
          </ActionIcon>
          <Typography variant='body-lg' fw={500}>
            {totalCount > 0 && currentIndex >= 0
              ? `${currentIndex + 1}/${totalCount}`
              : '-/-'}
          </Typography>
          <ActionIcon
            variant='default'
            size={40}
            onClick={onNext}
            disabled={
              !opened || totalCount <= 0 || currentIndex >= totalCount - 1
            }
            aria-label='Next SQL'
          >
            <IconChevronRight size={18} />
          </ActionIcon>
        </Flex>
      </DetailsDrawer.Footer>
    </DetailsDrawer>
  )
}

export default SQLExecutionPlanDrawer
