import { Box, useTheme } from '@mui/material'
import type { Ref } from 'react'
import {
  memo,
  useCallback,
  useEffect,
  useImperativeHandle,
  useMemo,
  useReducer,
  useRef,
  useState,
} from 'react'
import { useTranslation } from 'react-i18next'

import { useTrafficGraphDataEnhanced } from '@/hooks/use-traffic-monitor'
import { useVerge } from '@/hooks/use-verge'
import { debugLog } from '@/utils/debug'
import parseTraffic from '@/utils/parse-traffic'

// 流量数据项接口
interface ITrafficItem {
  up: number
  down: number
  timestamp?: number
}

// 对外暴露的接口
export interface EnhancedCanvasTrafficGraphRef {
  appendData: (data: ITrafficItem) => void
  toggleStyle: () => void
}

type TimeRange = 1 | 5 | 10 // 分钟

// 悬浮提示数据接口
interface TooltipData {
  x: number
  y: number
  upSpeed: string
  downSpeed: string
  timestamp: string
  visible: boolean
  dataIndex: number // 添加数据索引用于高亮
  highlightY: number // 高亮Y轴位置
}

const MAX_POINTS = 300
const TARGET_FPS = 15 // 降低帧率减少闪烁
const LINE_WIDTH_UP = 2.5
const LINE_WIDTH_DOWN = 2.5
const LINE_WIDTH_GRID = 0.5
const ALPHA_GRADIENT = 0.15 // 降低渐变透明度
const ALPHA_LINE = 0.9
const PADDING_TOP = 16
const PADDING_RIGHT = 16 // 增加右边距确保时间戳完整显示
const PADDING_BOTTOM = 32 // 进一步增加底部空间给时间轴和统计信息
const PADDING_LEFT = 35 // 增加左边距为Y轴标签留出空间

const GRAPH_CONFIG = {
  maxPoints: MAX_POINTS,
  targetFPS: TARGET_FPS,
  lineWidth: {
    up: LINE_WIDTH_UP,
    down: LINE_WIDTH_DOWN,
    grid: LINE_WIDTH_GRID,
  },
  alpha: {
    gradient: ALPHA_GRADIENT,
    line: ALPHA_LINE,
  },
  padding: {
    top: PADDING_TOP,
    right: PADDING_RIGHT,
    bottom: PADDING_BOTTOM,
    left: PADDING_LEFT,
  },
}

const MIN_FPS = 8
const MAX_FPS = 20
const FPS_ADJUST_INTERVAL = 3000 // ms
const FPS_SAMPLE_WINDOW = 12
const STALE_DATA_THRESHOLD = 2500 // ms without fresh data => drop FPS
const RESUME_FPS_TARGET = 12
const RESUME_COOLDOWN_MS = 2000

const getNow = () =>
  typeof performance !== 'undefined' ? performance.now() : Date.now()

interface EnhancedCanvasTrafficGraphProps {
  ref?: Ref<EnhancedCanvasTrafficGraphRef>
}

const displayDataReducer = (
  _: ITrafficDataPoint[],
  payload: ITrafficDataPoint[],
): ITrafficDataPoint[] => payload

/**
 * 稳定版Canvas流量图表组件
 * 修复闪烁问题，添加时间轴显示
 */
export const EnhancedCanvasTrafficGraph = memo(
  function EnhancedCanvasTrafficGraph({
    ref,
  }: EnhancedCanvasTrafficGraphProps) {
    const theme = useTheme()
    const { t } = useTranslation()
    const verge = useVerge()
    const pause_render_traffic_stats_on_blur =
      verge.verge?.pause_render_traffic_stats_on_blur ?? true

    // 使用增强版全局流量数据管理
    const { dataPoints, requestRange, samplerStats } =
      useTrafficGraphDataEnhanced()

    // 基础状态
    const [timeRange, setTimeRange] = useState<TimeRange>(10)
    const [chartStyle, setChartStyle] = useState<'bezier' | 'line'>('bezier')

    const initialFocusState =
      typeof document !== 'undefined' ? !document.hidden : true
    const [isWindowFocused, setIsWindowFocused] = useState(initialFocusState)

    // 悬浮提示状态
    const [tooltipData, setTooltipData] = useState<TooltipData>({
      x: 0,
      y: 0,
      upSpeed: '',
      downSpeed: '',
      timestamp: '',
      visible: false,
      dataIndex: -1,
      highlightY: 0,
    })

    // Canvas引用和渲染状态
    const canvasRef = useRef<HTMLCanvasElement>(null)
    const animationFrameRef = useRef<number | undefined>(undefined)
    const lastRenderTimeRef = useRef<number>(0)
    const isInitializedRef = useRef<boolean>(false)
    const isWindowFocusedRef = useRef<boolean>(initialFocusState)
    const fpsControllerRef = useRef<{
      target: number
      samples: number[]
      lastAdjustTime: number
    }>({
      target: GRAPH_CONFIG.targetFPS,
      samples: [],
      lastAdjustTime: 0,
    })
    const lastDataTimestampRef = useRef<number>(0)
    const resumeCooldownRef = useRef<number>(0)
    const dataStaleRef = useRef<boolean>(false)

    // 当前显示的数据缓存
    const [displayData, dispatchDisplayData] = useReducer(
      displayDataReducer,
      [],
    )
    const debounceTimeoutRef = useRef<number | null>(null)
    const [currentFPS, setCurrentFPS] = useState(GRAPH_CONFIG.targetFPS)

    // 主题颜色配置
    const colors = useMemo(
      () => ({
        up: theme.palette.secondary.main,
        down: theme.palette.primary.main,
        grid: theme.palette.divider,
        text: theme.palette.text.secondary,
        background: theme.palette.background.paper,
      }),
      [theme],
    )

    // 更新显示数据（防抖处理）
    const updateDisplayData = useCallback((newData: ITrafficDataPoint[]) => {
      if (debounceTimeoutRef.current !== null) {
        window.clearTimeout(debounceTimeoutRef.current)
      }
      debounceTimeoutRef.current = window.setTimeout(() => {
        dispatchDisplayData(newData)
      }, 50) // 50ms防抖
    }, [])

    // 监听数据变化
    useEffect(() => {
      updateDisplayData(dataPoints)

      return () => {
        if (debounceTimeoutRef.current !== null) {
          window.clearTimeout(debounceTimeoutRef.current)
          debounceTimeoutRef.current = null
        }
      }
    }, [dataPoints, updateDisplayData])

    useEffect(() => {
      requestRange(timeRange)
    }, [requestRange, timeRange])

    useEffect(() => {
      if (displayData.length === 0) {
        lastDataTimestampRef.current = 0
        dataStaleRef.current = false
        fpsControllerRef.current.target = GRAPH_CONFIG.targetFPS
        fpsControllerRef.current.samples = []
        fpsControllerRef.current.lastAdjustTime = 0
        // eslint-disable-next-line @eslint-react/set-state-in-effect
        setCurrentFPS(GRAPH_CONFIG.targetFPS)
        return
      }

      const latestTimestamp =
        displayData[displayData.length - 1]?.timestamp ?? null
      if (latestTimestamp) {
        lastDataTimestampRef.current = latestTimestamp
        const age = Date.now() - latestTimestamp
        const stale = age > STALE_DATA_THRESHOLD
        dataStaleRef.current = stale
      } else {
        dataStaleRef.current = false
      }
    }, [displayData])

    const handleFocusStateChange = useCallback(
      (focused: boolean) => {
        isWindowFocusedRef.current = focused
        setIsWindowFocused(focused)

        const highResNow = getNow()
        lastRenderTimeRef.current = highResNow

        if (focused || !pause_render_traffic_stats_on_blur) {
          resumeCooldownRef.current = Date.now()
          const controller = fpsControllerRef.current
          const resumeTarget = Math.max(
            MIN_FPS,
            Math.min(controller.target, RESUME_FPS_TARGET),
          )
          controller.target = resumeTarget
          controller.samples = []
          controller.lastAdjustTime = 0
          setCurrentFPS(resumeTarget)
        } else {
          resumeCooldownRef.current = 0
        }
      },
      [setIsWindowFocused, setCurrentFPS, pause_render_traffic_stats_on_blur],
    )

    useEffect(() => {
      if (typeof window === 'undefined' || typeof document === 'undefined') {
        return
      }

      const handleFocus = () => handleFocusStateChange(true)
      const handleBlur = () => handleFocusStateChange(false)
      const handleVisibilityChange = () =>
        handleFocusStateChange(!document.hidden)

      window.addEventListener('focus', handleFocus)
      window.addEventListener('blur', handleBlur)
      document.addEventListener('visibilitychange', handleVisibilityChange)

      return () => {
        window.removeEventListener('focus', handleFocus)
        window.removeEventListener('blur', handleBlur)
        document.removeEventListener('visibilitychange', handleVisibilityChange)
      }
    }, [handleFocusStateChange])

    // Y轴坐标计算 - 基于刻度范围的线性映射
    const calculateY = useCallback(
      (value: number, height: number, data: ITrafficDataPoint[]): number => {
        const padding = GRAPH_CONFIG.padding
        const topY = padding.top + 10 // 与刻度系统保持一致
        const bottomY = height - padding.bottom - 5

        if (data.length === 0) return bottomY

        // 获取当前的刻度范围
        const allValues = [...data.map((d) => d.up), ...data.map((d) => d.down)]
        const maxValue = Math.max(...allValues)
        const minValue = Math.min(...allValues)

        let topValue, bottomValue

        if (maxValue === 0) {
          topValue = 1024
          bottomValue = 0
        } else {
          const range = maxValue - minValue
          const padding_percent = range > 0 ? 0.1 : 0.5

          if (range === 0) {
            bottomValue = 0
            topValue = maxValue * 1.2
          } else {
            bottomValue = Math.max(0, minValue - range * padding_percent)
            topValue = maxValue + range * padding_percent
          }
        }

        // 线性映射到Y坐标
        if (topValue === bottomValue) return bottomY

        const ratio = (value - bottomValue) / (topValue - bottomValue)
        return bottomY - ratio * (bottomY - topY)
      },
      [],
    )

    // 鼠标悬浮处理 - 计算最近的数据点
    const handleMouseMove = useCallback(
      (event: React.MouseEvent<HTMLCanvasElement>) => {
        const canvas = canvasRef.current
        if (!canvas || displayData.length === 0) return

        const rect = canvas.getBoundingClientRect()
        const mouseX = event.clientX - rect.left
        const mouseY = event.clientY - rect.top

        const padding = GRAPH_CONFIG.padding
        const effectiveWidth = rect.width - padding.left - padding.right

        // 计算最接近的数据点索引
        const relativeMouseX = mouseX - padding.left
        const ratio = Math.max(0, Math.min(1, relativeMouseX / effectiveWidth))
        const dataIndex = Math.round(ratio * (displayData.length - 1))

        if (dataIndex >= 0 && dataIndex < displayData.length) {
          const dataPoint = displayData[dataIndex]

          // 格式化流量数据
          const [upValue, upUnit] = parseTraffic(dataPoint.up)
          const [downValue, downUnit] = parseTraffic(dataPoint.down)

          // 格式化时间戳
          const timeStr = dataPoint.timestamp
            ? new Date(dataPoint.timestamp).toLocaleTimeString('zh-CN', {
                hour: '2-digit',
                minute: '2-digit',
                second: '2-digit',
              })
            : '未知时间'

          // 计算数据点对应的Y坐标位置（用于高亮）
          const upY = calculateY(dataPoint.up, rect.height, displayData)
          const downY = calculateY(dataPoint.down, rect.height, displayData)
          const highlightY =
            Math.max(dataPoint.up, dataPoint.down) === dataPoint.up
              ? upY
              : downY

          setTooltipData({
            x: mouseX,
            y: mouseY,
            upSpeed: `${upValue}${upUnit}/s`,
            downSpeed: `${downValue}${downUnit}/s`,
            timestamp: timeStr,
            visible: true,
            dataIndex,
            highlightY,
          })
        }
      },
      [displayData, calculateY],
    )

    // 鼠标离开处理
    const handleMouseLeave = useCallback(() => {
      setTooltipData((prev) => ({ ...prev, visible: false }))
    }, [])

    // 获取智能Y轴刻度（三刻度系统：最小值、中间值、最大值）
    const getYAxisTicks = useCallback(
      (data: ITrafficDataPoint[], height: number) => {
        if (data.length === 0) return []

        // 找到数据的最大值和最小值
        const allValues = [...data.map((d) => d.up), ...data.map((d) => d.down)]
        const maxValue = Math.max(...allValues)
        const minValue = Math.min(...allValues)

        // 格式化流量数值
        const formatTrafficValue = (bytes: number): string => {
          if (bytes === 0) return '0'
          if (bytes < 1024) return `${Math.round(bytes)}B`
          if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)}KB`
          return `${(bytes / (1024 * 1024)).toFixed(1)}MB`
        }

        const padding = GRAPH_CONFIG.padding

        // 强制显示三个刻度：底部、中间、顶部
        const topY = padding.top + 10 // 避免与顶部时间范围按钮重叠
        const bottomY = height - padding.bottom - 5 // 避免与底部时间轴重叠
        const middleY = (topY + bottomY) / 2

        // 计算对应的值
        let topValue, middleValue, bottomValue

        if (maxValue === 0) {
          // 如果没有流量，显示0到一个小值的范围
          topValue = 1024 // 1KB
          middleValue = 512 // 512B
          bottomValue = 0
        } else {
          // 根据数据范围计算合适的刻度值
          const range = maxValue - minValue
          const padding_percent = range > 0 ? 0.1 : 0.5 // 如果范围为0，使用更大的边距

          if (range === 0) {
            // 所有值相同的情况
            bottomValue = 0
            middleValue = maxValue * 0.5
            topValue = maxValue * 1.2
          } else {
            // 正常情况
            bottomValue = Math.max(0, minValue - range * padding_percent)
            topValue = maxValue + range * padding_percent
            middleValue = (bottomValue + topValue) / 2
          }
        }

        // 创建三个固定位置的刻度
        const ticks = [
          {
            value: bottomValue,
            label: formatTrafficValue(bottomValue),
            y: bottomY,
          },
          {
            value: middleValue,
            label: formatTrafficValue(middleValue),
            y: middleY,
          },
          {
            value: topValue,
            label: formatTrafficValue(topValue),
            y: topY,
          },
        ]

        return ticks
      },
      [],
    )

    // 绘制Y轴刻度线和标签
    const drawYAxis = useCallback(
      (
        ctx: CanvasRenderingContext2D,
        width: number,
        height: number,
        data: ITrafficDataPoint[],
      ) => {
        const padding = GRAPH_CONFIG.padding
        const ticks = getYAxisTicks(data, height)

        if (ticks.length === 0) return

        ctx.save()

        ticks.forEach((tick, index) => {
          const isBottomTick = index === 0 // 最底部的刻度
          const isTopTick = index === ticks.length - 1 // 最顶部的刻度

          // 绘制水平刻度线，只绘制关键刻度线
          if (isBottomTick || isTopTick) {
            ctx.strokeStyle = colors.grid
            ctx.lineWidth = isBottomTick ? 0.8 : 0.4 // 底部刻度线稍粗
            ctx.globalAlpha = isBottomTick ? 0.25 : 0.15

            ctx.beginPath()
            ctx.moveTo(padding.left, tick.y)
            ctx.lineTo(width - padding.right, tick.y)
            ctx.stroke()
          }

          // 绘制Y轴标签
          ctx.fillStyle = colors.text
          ctx.font =
            "8px -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif"
          ctx.globalAlpha = 0.9
          ctx.textAlign = 'right'
          ctx.textBaseline = 'middle'

          // 为标签添加更清晰的背景（仅在必要时）
          if (tick.label !== '0') {
            const labelWidth = ctx.measureText(tick.label).width
            ctx.globalAlpha = 0.15
            ctx.fillStyle = colors.background
            ctx.fillRect(
              padding.left - labelWidth - 8,
              tick.y - 5,
              labelWidth + 4,
              10,
            )
          }

          // 绘制标签文字
          ctx.globalAlpha = 0.9
          ctx.fillStyle = colors.text
          ctx.fillText(tick.label, padding.left - 4, tick.y)
        })

        ctx.restore()
      },
      [colors.grid, colors.text, colors.background, getYAxisTicks],
    )

    // 获取时间范围对应的最佳时间显示策略
    const getTimeDisplayStrategy = useCallback(
      (timeRangeMinutes: TimeRange) => {
        switch (timeRangeMinutes) {
          case 1: // 1分钟：更密集的时间标签，显示 MM:SS
            return {
              maxLabels: 6, // 减少到6个，更适合短时间
              formatTime: (timestamp: number) => {
                const date = new Date(timestamp)
                const minutes = date.getMinutes().toString().padStart(2, '0')
                const seconds = date.getSeconds().toString().padStart(2, '0')
                return `${minutes}:${seconds}` // 显示 MM:SS
              },
              intervalSeconds: 10, // 每10秒一个标签，更合理
              minPixelDistance: 35, // 减少间距，允许更多标签
            }
          case 5: // 5分钟：中等密度，显示 HH:MM
            return {
              maxLabels: 6, // 6个标签比较合适
              formatTime: (timestamp: number) => {
                const date = new Date(timestamp)
                return date.toLocaleTimeString('en-US', {
                  hour12: false,
                  hour: '2-digit',
                  minute: '2-digit',
                }) // 显示 HH:MM
              },
              intervalSeconds: 30, // 约30秒间隔
              minPixelDistance: 38, // 减少间距，允许更多标签
            }
          case 10: // 10分钟：标准密度，显示 HH:MM
          default:
            return {
              maxLabels: 8, // 保持8个
              formatTime: (timestamp: number) => {
                const date = new Date(timestamp)
                return date.toLocaleTimeString('en-US', {
                  hour12: false,
                  hour: '2-digit',
                  minute: '2-digit',
                }) // 显示 HH:MM
              },
              intervalSeconds: 60, // 1分钟间隔
              minPixelDistance: 40, // 减少间距，允许更多标签
            }
        }
      },
      [],
    )

    // 绘制时间轴
    const drawTimeAxis = useCallback(
      (
        ctx: CanvasRenderingContext2D,
        width: number,
        height: number,
        data: ITrafficDataPoint[],
      ) => {
        if (data.length === 0) return

        const padding = GRAPH_CONFIG.padding
        const effectiveWidth = width - padding.left - padding.right
        const timeAxisY = height - padding.bottom + 14

        const strategy = getTimeDisplayStrategy(timeRange)

        ctx.save()
        ctx.fillStyle = colors.text
        ctx.font =
          "10px -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif"
        ctx.globalAlpha = 0.7

        // 根据数据长度和时间范围智能选择显示间隔
        const targetLabels = Math.min(strategy.maxLabels, data.length)
        const step = Math.max(1, Math.floor(data.length / (targetLabels - 1)))

        // 使用策略中定义的最小像素间距
        const minPixelDistance = strategy.minPixelDistance || 45
        const actualStep = Math.max(
          step,
          Math.ceil((data.length * minPixelDistance) / effectiveWidth),
        )

        // 收集要显示的时间点
        const timePoints: Array<{ index: number; x: number; label: string }> =
          []

        // 添加第一个时间点
        if (data.length > 0 && data[0].timestamp) {
          timePoints.push({
            index: 0,
            x: padding.left,
            label: strategy.formatTime(data[0].timestamp),
          })
        }

        // 添加中间的时间点
        for (
          let i = actualStep;
          i < data.length - actualStep;
          i += actualStep
        ) {
          const point = data[i]
          if (!point.timestamp) continue

          const x = padding.left + (i / (data.length - 1)) * effectiveWidth
          timePoints.push({
            index: i,
            x,
            label: strategy.formatTime(point.timestamp),
          })
        }

        // 添加最后一个时间点（如果不会与前面的重叠）
        if (data.length > 1 && data[data.length - 1].timestamp) {
          const lastX = width - padding.right
          const lastPoint = timePoints[timePoints.length - 1]

          // 确保最后一个标签与前一个标签有足够间距
          if (!lastPoint || lastX - lastPoint.x >= minPixelDistance) {
            timePoints.push({
              index: data.length - 1,
              x: lastX,
              label: strategy.formatTime(data[data.length - 1].timestamp),
            })
          }
        }

        // 绘制时间标签
        timePoints.forEach((point, index) => {
          if (index === 0) {
            // 第一个标签左对齐
            ctx.textAlign = 'left'
          } else if (index === timePoints.length - 1) {
            // 最后一个标签右对齐
            ctx.textAlign = 'right'
          } else {
            // 中间标签居中对齐
            ctx.textAlign = 'center'
          }

          ctx.fillText(point.label, point.x, timeAxisY)
        })

        ctx.restore()
      },
      [colors.text, timeRange, getTimeDisplayStrategy],
    )

    // 绘制网格线
    const drawGrid = useCallback(
      (ctx: CanvasRenderingContext2D, width: number, height: number) => {
        const padding = GRAPH_CONFIG.padding
        const effectiveWidth = width - padding.left - padding.right
        const effectiveHeight = height - padding.top - padding.bottom

        ctx.save()
        ctx.strokeStyle = colors.grid
        ctx.lineWidth = GRAPH_CONFIG.lineWidth.grid
        ctx.globalAlpha = 0.7

        // 水平网格线
        const horizontalLines = 4
        for (let i = 1; i <= horizontalLines; i++) {
          const y = padding.top + (effectiveHeight / (horizontalLines + 1)) * i
          ctx.beginPath()
          ctx.moveTo(padding.left, y)
          ctx.lineTo(width - padding.right, y)
          ctx.stroke()
        }

        // 垂直网格线
        const verticalLines = 6
        for (let i = 1; i <= verticalLines; i++) {
          const x = padding.left + (effectiveWidth / (verticalLines + 1)) * i
          ctx.beginPath()
          ctx.moveTo(x, padding.top)
          ctx.lineTo(x, height - padding.bottom)
          ctx.stroke()
        }

        ctx.restore()
      },
      [colors.grid],
    )

    // 绘制流量线条
    const drawTrafficLine = useCallback(
      (
        ctx: CanvasRenderingContext2D,
        values: number[],
        width: number,
        height: number,
        color: string,
        withGradient = false,
        data: ITrafficDataPoint[],
      ) => {
        if (values.length < 2) return

        const padding = GRAPH_CONFIG.padding
        const effectiveWidth = width - padding.left - padding.right

        const points = values.map((value, index) => [
          padding.left + (index / (values.length - 1)) * effectiveWidth,
          calculateY(value, height, data),
        ])

        ctx.save()

        // 绘制渐变填充
        if (withGradient && chartStyle === 'bezier') {
          const gradient = ctx.createLinearGradient(
            0,
            padding.top,
            0,
            height - padding.bottom,
          )
          gradient.addColorStop(
            0,
            `${color}${Math.round(GRAPH_CONFIG.alpha.gradient * 255)
              .toString(16)
              .padStart(2, '0')}`,
          )
          gradient.addColorStop(1, `${color}00`)

          ctx.beginPath()
          ctx.moveTo(points[0][0], points[0][1])

          if (chartStyle === 'bezier') {
            for (let i = 1; i < points.length; i++) {
              const current = points[i]
              const next = points[i + 1] || current
              const controlX = (current[0] + next[0]) / 2
              const controlY = (current[1] + next[1]) / 2
              ctx.quadraticCurveTo(current[0], current[1], controlX, controlY)
            }
          } else {
            for (let i = 1; i < points.length; i++) {
              ctx.lineTo(points[i][0], points[i][1])
            }
          }

          ctx.lineTo(points[points.length - 1][0], height - padding.bottom)
          ctx.lineTo(points[0][0], height - padding.bottom)
          ctx.closePath()
          ctx.fillStyle = gradient
          ctx.fill()
        }

        // 绘制主线条
        ctx.beginPath()
        ctx.strokeStyle = color
        ctx.lineWidth = GRAPH_CONFIG.lineWidth.up
        ctx.lineCap = 'round'
        ctx.lineJoin = 'round'
        ctx.globalAlpha = GRAPH_CONFIG.alpha.line

        ctx.moveTo(points[0][0], points[0][1])

        if (chartStyle === 'bezier') {
          for (let i = 1; i < points.length; i++) {
            const current = points[i]
            const next = points[i + 1] || current
            const controlX = (current[0] + next[0]) / 2
            const controlY = (current[1] + next[1]) / 2
            ctx.quadraticCurveTo(current[0], current[1], controlX, controlY)
          }
        } else {
          for (let i = 1; i < points.length; i++) {
            ctx.lineTo(points[i][0], points[i][1])
          }
        }

        ctx.stroke()
        ctx.restore()
      },
      [calculateY, chartStyle],
    )

    // 主绘制函数
    const drawGraph = useCallback(() => {
      const canvas = canvasRef.current
      if (!canvas || displayData.length === 0) return

      const ctx = canvas.getContext('2d')
      if (!ctx) return

      // Compute CSS size and pixel buffer size.
      // Note: WebView2 on Windows may return fractional CSS sizes after maximize.
      // We round pixel buffer to integers to avoid 1px gaps/cropping artifacts.
      const rect = canvas.getBoundingClientRect()
      const dpr = window.devicePixelRatio || 1
      const cssWidth = rect.width
      const cssHeight = rect.height
      const pixelWidth = Math.max(1, Math.floor(cssWidth * dpr))
      const pixelHeight = Math.max(1, Math.floor(cssHeight * dpr))

      // Keep CSS-driven sizing so the canvas stretches with its container (e.g., on maximize).
      if (canvas.style.width !== '100%') {
        canvas.style.width = '100%'
      }
      if (canvas.style.height !== '100%') {
        canvas.style.height = '100%'
      }

      if (canvas.width !== pixelWidth || canvas.height !== pixelHeight) {
        canvas.width = pixelWidth
        canvas.height = pixelHeight
        // Reset transform before scaling to avoid cumulative scaling offsets.
        ctx.setTransform(1, 0, 0, 1, 0, 0)
        ctx.scale(dpr, dpr) // map CSS units to device pixels
      }

      // Clear using CSS dimensions; context is already scaled by DPR.
      ctx.clearRect(0, 0, cssWidth, cssHeight)

      // 绘制Y轴刻度线（背景层）
      drawYAxis(ctx, cssWidth, cssHeight, displayData)

      // 绘制网格
      drawGrid(ctx, cssWidth, cssHeight)

      // 绘制时间轴
      drawTimeAxis(ctx, cssWidth, cssHeight, displayData)

      // 提取流量数据
      const upValues = displayData.map((d) => d.up)
      const downValues = displayData.map((d) => d.down)

      // 绘制下载线（背景层）
      drawTrafficLine(
        ctx,
        downValues,
        cssWidth,
        cssHeight,
        colors.down,
        true,
        displayData,
      )

      // 绘制上传线（前景层）
      drawTrafficLine(
        ctx,
        upValues,
        cssWidth,
        cssHeight,
        colors.up,
        true,
        displayData,
      )

      // 绘制悬浮高亮线
      if (tooltipData.visible && tooltipData.dataIndex >= 0) {
        const padding = GRAPH_CONFIG.padding
        const effectiveWidth = cssWidth - padding.left - padding.right
        const dataX =
          padding.left +
          (tooltipData.dataIndex / (displayData.length - 1)) * effectiveWidth

        ctx.save()
        ctx.strokeStyle = colors.text
        ctx.lineWidth = 1
        ctx.globalAlpha = 0.6
        ctx.setLineDash([4, 4]) // 虚线效果

        // 绘制垂直指示线
        ctx.beginPath()
        ctx.moveTo(dataX, padding.top)
        ctx.lineTo(dataX, cssHeight - padding.bottom)
        ctx.stroke()

        // 绘制水平指示线（高亮Y轴位置）
        ctx.beginPath()
        ctx.moveTo(padding.left, tooltipData.highlightY)
        ctx.lineTo(cssWidth - padding.right, tooltipData.highlightY)
        ctx.stroke()

        ctx.restore()
      }

      isInitializedRef.current = true
    }, [
      displayData,
      colors,
      drawYAxis,
      drawGrid,
      drawTimeAxis,
      drawTrafficLine,
      tooltipData,
    ])

    const collectFrameSample = useCallback(
      (renderDuration: number, frameBudget: number) => {
        const controller = fpsControllerRef.current
        controller.samples.push(renderDuration)
        if (controller.samples.length > FPS_SAMPLE_WINDOW) {
          controller.samples.shift()
        }

        const perfNow = getNow()
        const lastDataAge =
          lastDataTimestampRef.current > 0
            ? Date.now() - lastDataTimestampRef.current
            : null
        const isDataStale =
          typeof lastDataAge === 'number' && lastDataAge > STALE_DATA_THRESHOLD

        let inResumeCooldown = false
        if (resumeCooldownRef.current) {
          const elapsedSinceResume = Date.now() - resumeCooldownRef.current
          if (elapsedSinceResume < RESUME_COOLDOWN_MS) {
            inResumeCooldown = true
          } else {
            resumeCooldownRef.current = 0
          }
        }

        if (isDataStale && controller.target !== MIN_FPS) {
          controller.target = MIN_FPS
          controller.samples = []
          controller.lastAdjustTime = perfNow
          setCurrentFPS(controller.target)
          return
        }

        if (
          !isDataStale &&
          !inResumeCooldown &&
          controller.target < GRAPH_CONFIG.targetFPS
        ) {
          controller.target = Math.min(
            GRAPH_CONFIG.targetFPS,
            controller.target + 2,
          )
          controller.samples = []
          controller.lastAdjustTime = perfNow
          setCurrentFPS(controller.target)
        }

        if (
          controller.lastAdjustTime !== 0 &&
          perfNow - controller.lastAdjustTime < FPS_ADJUST_INTERVAL
        ) {
          return
        }

        if (controller.samples.length === 0) return

        const avgRender =
          controller.samples.reduce((sum, value) => sum + value, 0) /
          controller.samples.length

        let nextTarget = controller.target

        if (avgRender > frameBudget * 0.75 && controller.target > MIN_FPS) {
          nextTarget = Math.max(MIN_FPS, controller.target - 2)
        } else if (
          avgRender < Math.max(4, frameBudget * 0.4) &&
          controller.target < MAX_FPS &&
          !inResumeCooldown
        ) {
          nextTarget = Math.min(MAX_FPS, controller.target + 2)
        }

        controller.samples = []
        controller.lastAdjustTime = perfNow

        if (nextTarget !== controller.target) {
          controller.target = nextTarget
          setCurrentFPS(nextTarget)
        }
      },
      [setCurrentFPS],
    )

    // 受控的动画循环
    useEffect(() => {
      if (
        (!isWindowFocused && pause_render_traffic_stats_on_blur) ||
        displayData.length === 0 ||
        dataStaleRef.current
      ) {
        if (animationFrameRef.current) {
          cancelAnimationFrame(animationFrameRef.current)
          animationFrameRef.current = undefined
        }
        lastRenderTimeRef.current = getNow()
        return
      }

      const animate = (currentTime: number) => {
        if (!isWindowFocusedRef.current && pause_render_traffic_stats_on_blur) {
          lastRenderTimeRef.current = getNow()
          animationFrameRef.current = undefined
          return
        }

        const lastDataAge =
          lastDataTimestampRef.current > 0
            ? Date.now() - lastDataTimestampRef.current
            : null
        const targetFPS = fpsControllerRef.current.target
        const frameBudget = 1000 / targetFPS

        if (
          typeof lastDataAge === 'number' &&
          lastDataAge > STALE_DATA_THRESHOLD
        ) {
          if (animationFrameRef.current) {
            cancelAnimationFrame(animationFrameRef.current)
            animationFrameRef.current = undefined
          }
          dataStaleRef.current = true
          return
        }

        if (
          currentTime - lastRenderTimeRef.current >= frameBudget ||
          !isInitializedRef.current
        ) {
          const drawStart = getNow()
          drawGraph()
          const drawEnd = getNow()

          lastRenderTimeRef.current = currentTime
          collectFrameSample(drawEnd - drawStart, frameBudget)
        }

        animationFrameRef.current = requestAnimationFrame(animate)
      }

      animationFrameRef.current = requestAnimationFrame(animate)

      return () => {
        if (animationFrameRef.current) {
          cancelAnimationFrame(animationFrameRef.current)
          animationFrameRef.current = undefined
        }
      }
    }, [
      drawGraph,
      displayData.length,
      isWindowFocused,
      pause_render_traffic_stats_on_blur,
      collectFrameSample,
    ])

    // 切换时间范围
    const handleTimeRangeClick = useCallback((event: React.MouseEvent) => {
      event.stopPropagation()
      setTimeRange((prev) => {
        return prev === 1 ? 5 : prev === 5 ? 10 : 1
      })
    }, [])

    // 切换图表样式
    const toggleStyle = useCallback(() => {
      setChartStyle((prev) => (prev === 'bezier' ? 'line' : 'bezier'))
    }, [])

    // 兼容性方法
    const appendData = useCallback((data: ITrafficItem) => {
      debugLog(
        '[EnhancedCanvasTrafficGraphV2] appendData called (using global data):',
        data,
      )
    }, [])

    // 暴露方法给父组件
    useImperativeHandle(
      ref,
      () => ({
        appendData,
        toggleStyle,
      }),
      [appendData, toggleStyle],
    )

    // 获取时间范围文本
    const getTimeRangeText = useCallback(() => {
      return t('home.components.traffic.patterns.minutes', {
        time: timeRange,
      })
    }, [timeRange, t])

    return (
      <Box
        sx={{
          width: '100%',
          height: '100%',
          position: 'relative',
          bgcolor: 'action.hover',
          borderRadius: 1,
          cursor: 'pointer',
          overflow: 'hidden',
        }}
        onClick={toggleStyle}
      >
        <canvas
          ref={canvasRef}
          style={{
            width: '100%',
            height: '100%',
            display: 'block',
          }}
          onMouseMove={handleMouseMove}
          onMouseLeave={handleMouseLeave}
          onClick={toggleStyle}
        />

        {/* 控制层覆盖 */}
        <Box
          sx={{
            position: 'absolute',
            top: 0,
            left: 0,
            right: 0,
            bottom: 0,
            pointerEvents: 'none',
          }}
        >
          {/* 时间范围按钮 */}
          <Box
            component="div"
            onClick={handleTimeRangeClick}
            sx={{
              position: 'absolute',
              top: 6,
              left: 40, // 向右移动，避免与Y轴最大值标签重叠
              fontSize: '11px',
              fontWeight: 'bold',
              color: 'text.secondary',
              cursor: 'pointer',
              pointerEvents: 'all',
              px: 1,
              py: 0.5,
              borderRadius: 0.5,
              bgcolor: 'rgba(0,0,0,0.05)',
              '&:hover': {
                bgcolor: 'rgba(0,0,0,0.1)',
              },
            }}
          >
            {getTimeRangeText()}
          </Box>

          {/* 图例 */}
          <Box
            sx={{
              position: 'absolute',
              top: 6,
              right: 8,
              display: 'flex',
              flexDirection: 'column',
              gap: 0.5,
            }}
          >
            <Box
              sx={{
                fontSize: '11px',
                fontWeight: 'bold',
                color: colors.up,
                textAlign: 'right',
              }}
            >
              {t('home.components.traffic.legends.upload')}
            </Box>
            <Box
              sx={{
                fontSize: '11px',
                fontWeight: 'bold',
                color: colors.down,
                textAlign: 'right',
              }}
            >
              {t('home.components.traffic.legends.download')}
            </Box>
          </Box>

          {/* 样式指示器 */}
          <Box
            sx={{
              position: 'absolute',
              bottom: 6,
              right: 8,
              fontSize: '10px',
              color: 'text.disabled',
              opacity: 0.7,
            }}
          >
            {chartStyle === 'bezier' ? 'Smooth' : 'Linear'}
          </Box>

          {/* 数据统计指示器（左下角） */}
          <Box
            sx={{
              position: 'absolute',
              bottom: 6,
              left: 8,
              fontSize: '9px',
              color: 'text.disabled',
              opacity: 0.6,
              lineHeight: 1.2,
            }}
          >
            Points: {displayData.length} | Compressed:{' '}
            {samplerStats.compressedBufferSize} | FPS: {currentFPS}
          </Box>

          {/* 悬浮提示框 */}
          {tooltipData.visible && (
            <Box
              sx={{
                position: 'absolute',
                left: tooltipData.x + 8,
                top: tooltipData.y - 8,
                bgcolor: theme.palette.background.paper,
                border: 1,
                borderColor: 'divider',
                borderRadius: 0.5,
                px: 1,
                py: 0.5,
                fontSize: '10px',
                lineHeight: 1.2,
                zIndex: 1000,
                pointerEvents: 'none',
                transform:
                  tooltipData.x > 200 ? 'translateX(-100%)' : 'translateX(0)',
                boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
                backdropFilter: 'none',
                opacity: 1,
                whiteSpace: 'nowrap',
              }}
            >
              <Box sx={{ color: 'text.secondary', mb: 0.2 }}>
                {tooltipData.timestamp}
              </Box>
              <Box sx={{ color: 'secondary.main', fontWeight: 500 }}>
                ↑ {tooltipData.upSpeed}
              </Box>
              <Box sx={{ color: 'primary.main', fontWeight: 500 }}>
                ↓ {tooltipData.downSpeed}
              </Box>
            </Box>
          )}
        </Box>
      </Box>
    )
  },
)

EnhancedCanvasTrafficGraph.displayName = 'EnhancedCanvasTrafficGraph'
