import { getValueFormat } from '@baurine/grafana-value-formats'
import { Axis, Chart, LineSeries, Position, ScaleType, Settings, TooltipStickTo, TooltipType } from '@elastic/charts'
import { useChartColors, useChartThemeConfig } from '@tidb-cloud-uikit/theme/Chart'
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 { useEffect, useMemo, useState } from 'react'

import { useTimeFormatter } from 'dbaas/components/TimeComponent'
import { formatSql } from 'dbaas/screens/NextGen/premium/shared/diagnosis/HighlightSQL'
import { DetailsDrawer } from 'dbaas/screens/NextGen/shared/DetailsDrawer'
import { eventTracking } from 'dbaas/utils/tracking'

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">
                  <Stack gap="xs">
                    <Typography variant="label-md" fw={500}>
                      Query Execution Plan
                    </Typography>
                    <CodeBlock foldProps={{ iconVisible: true, defaultHeight: 180 }} withBorder={false}>
                      {plan.planText}
                    </CodeBlock>
                  </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}>
                    <Table highlightOnHover horizontalSpacing={8} verticalSpacing={8}>
                      <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
