import React, { useRef, useEffect, useState, useCallback } from "react";
import vsSource from './glsl/timeline/vert.glsl';
import fsSource from './glsl/timeline/frag.glsl';
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { ChevronLeft, ChevronRight, Pause, Play } from "lucide-react";

import {
    Select,
    SelectContent,
    SelectGroup,
    SelectItem,
    SelectLabel,
    SelectTrigger,
    SelectValue,
} from "@/components/ui/select"
import { useTimeline } from "@/hooks/use-timeline";

interface Uniforms {
    startTimestamp: number;  // Unix 时间戳开始
    endTimestamp: number;    // Unix 时间戳结束 
    currentTimestamp: number; // 当前时间戳
    radius: number;
    d: number;
    timelineStartX: number;  // 时间轴在屏幕上的开始X坐标
    timelineEndX: number;    // 时间轴在屏幕上的结束X坐标
    viewportSize: [number, number];
    zoomLevel: number;       // 当前缩放级别
    panOffset: number;       // 当前平移偏移
}

interface Instants {
    position: Float32Array;
    color: Float32Array;
}

interface VesicaDataPoint {
    timestamp: number; // Unix 时间戳
    color?: [number, number, number, number]; // RGBA 颜色，默认为白色
}

interface Props extends React.HTMLAttributes<HTMLDivElement> {
    boxSize?: [number, number];
    startDate?: Date;
    endDate?: Date;
    currentDate?: Date;
    onDateChange?: (date: Date) => void;
    onPlay?: () => void;
    onPause?: () => void;
    minZoom?: number;  // 最小缩放级别
    maxZoom?: number;  // 最大缩放级别
    initialZoom?: number;  // 初始缩放级别
    vesicaData?: VesicaDataPoint[]; // vesica 实例数据
    dateFormat?: (timestamp: number) => string; // 自定义时间格式化函数
}

interface Status {
    isDragging: boolean;
    isLongPress: boolean;
    isPanningTimeline: boolean;
    customLineTimestamp: number | null; // 改为存储时间戳而不是屏幕坐标
    panOffset: number;
    zoomLevel: number;
}

interface RedrawOverrides {
    startDate?: Date;
    endDate?: Date;
    currentDate?: Date;
    zoomLevel?: number;
    panOffset?: number;
    customLineTimestamp?: number | null;
    isDragging?: boolean;
}

// 默认的vesica数据示例
const getDefaultVesicaData = (startDate?: Date, endDate?: Date): VesicaDataPoint[] => {
    if (!startDate || !endDate) return [];

    const start = startDate.getTime();
    const end = endDate.getTime();
    const timeRange = end - start;

    // 创建一些示例数据点
    return [
        {
            timestamp: start + timeRange * 0.1,
            color: [1.0, 0.2, 0.2, 0.8] // 红色
        },
        {
            timestamp: start + timeRange * 0.25,
            color: [0.2, 1.0, 0.2, 0.8] // 绿色
        },
        {
            timestamp: start + timeRange * 0.4,
            color: [0.2, 0.2, 1.0, 0.8] // 蓝色
        },
        {
            timestamp: start + timeRange * 0.6,
            color: [1.0, 1.0, 0.2, 0.8] // 黄色
        },
        {
            timestamp: start + timeRange * 0.75,
            color: [1.0, 0.2, 1.0, 0.8] // 紫色
        },
        {
            timestamp: start + timeRange * 0.9,
            color: [0.2, 1.0, 1.0, 0.8] // 青色
        }
    ];
};

function SelectDemo() {
    return (
        <Select>
            <SelectTrigger className="w-20">
                <SelectValue placeholder="Select a fruit" />
            </SelectTrigger>
            <SelectContent>
                <SelectGroup>
                    <SelectLabel>Fruits</SelectLabel>
                    <SelectItem value="apple">Apple</SelectItem>
                    <SelectItem value="banana">Banana</SelectItem>
                    <SelectItem value="blueberry">Blueberry</SelectItem>
                    <SelectItem value="grapes">Grapes</SelectItem>
                    <SelectItem value="pineapple">Pineapple</SelectItem>
                </SelectGroup>
            </SelectContent>
        </Select>
    )
}

export const Timeline: React.FC<Props> = ({
    startDate,
    endDate,
    currentDate,
    onDateChange,
    onPlay,
    onPause,
    boxSize = [4, 8],
    minZoom = 0.5,
    maxZoom = 8,
    initialZoom = 1,
    vesicaData,
    dateFormat,
    ...props
}) => {

    const canvasRef = useRef<HTMLCanvasElement>(null);
    const ticksCanvasRef = useRef<HTMLCanvasElement>(null);

    const { isPlaying, togglePlay } = useTimeline({
        initialDate: currentDate ?? new Date(),
        onDateChange(date) {
            onDateChange?.(date);
        }
    })

    const [state, setState] = useState<Status>({
        isDragging: false,
        isLongPress: false,
        isPanningTimeline: false,
        customLineTimestamp: currentDate?.getTime() ?? new Date().getTime(),
        panOffset: 0,
        zoomLevel: initialZoom,
    });

    const longPressTimerRef = useRef<NodeJS.Timeout | null>(null);
    const dragTempXRef = useRef<number | null>(null);
    const animationFrameRef = useRef<number | null>(null);

    const panStartXRef = useRef<number>(0);
    const panStartOffsetRef = useRef<number>(0);
    const panTempOffsetRef = useRef<number>(0);
    const hasDraggedTimelineRef = useRef<boolean>(false);

    const actualVesicaData = vesicaData ?? [];

    // 使用ref存储最新的状态值，避免闭包陷阱
    const stateRef = useRef(state);
    const propsRef = useRef({ startDate, endDate, currentDate });

    // 每次渲染时更新ref的值
    stateRef.current = state;
    propsRef.current = { startDate, endDate, currentDate };

    const forward = useCallback(() => {
        const newDate = new Date(state.customLineTimestamp! + 360000);
        setState({ ...state, customLineTimestamp: newDate.getTime() });
        onDateChange?.(newDate);
    }, [state.customLineTimestamp])

    // 缩放处理函数
    const handleZoom = (delta: number, mouseX?: number) => {
        const zoomFactor = 1.15; // 调整缩放因子，使缩放更平滑

        const newZoom = delta > 0
            ? Math.min(state.zoomLevel * zoomFactor, maxZoom)
            : Math.max(state.zoomLevel / zoomFactor, minZoom);

        // 如果缩放级别没有变化，直接返回
        if (newZoom === state.zoomLevel) return;

        // 基于鼠标位置的缩放（保持鼠标位置下的内容不变）
        let newPanOffset = state.panOffset;
        if (mouseX !== undefined && ticksCanvasRef.current && startDate && endDate) {
            const rect = ticksCanvasRef.current.getBoundingClientRect();
            const startX = 40; // 时间轴左边距，与drawTicks保持一致
            const endX = rect.width - 40; // 时间轴右边距
            const timelineWidth = endX - startX;

            // 计算总时间范围
            const timeRange = endDate.getTime() - startDate.getTime();

            // 计算当前可见时间窗口（缩放前）
            const currentVisibleTimeRange = timeRange / state.zoomLevel;
            const currentTimePerPixel = currentVisibleTimeRange / timelineWidth;
            const currentPanTimeOffset = -state.panOffset * currentTimePerPixel;
            const originalCenterTime = startDate.getTime() + timeRange / 2;
            const currentCenterTime = originalCenterTime + currentPanTimeOffset;
            const currentVisibleStartTime = currentCenterTime - currentVisibleTimeRange / 2;

            // 计算鼠标位置对应的时间点
            const mouseRelativeX = mouseX - startX;
            const mouseTimeProgress = mouseRelativeX / timelineWidth;
            const mouseTime = currentVisibleStartTime + mouseTimeProgress * currentVisibleTimeRange;

            // 计算缩放后的可见时间窗口
            const newVisibleTimeRange = timeRange / newZoom;
            const newTimePerPixel = newVisibleTimeRange / timelineWidth;

            // 计算新的中心时间，使鼠标位置对应的时间点保持不变
            const newVisibleStartTime = mouseTime - mouseTimeProgress * newVisibleTimeRange;
            const newCenterTime = newVisibleStartTime + newVisibleTimeRange / 2;
            const newPanTimeOffset = newCenterTime - originalCenterTime;
            newPanOffset = -newPanTimeOffset / newTimePerPixel;

            // 应用边界限制
            const maxPanOffset = 100 * newZoom;
            newPanOffset = Math.max(-maxPanOffset, Math.min(maxPanOffset, newPanOffset));
        }

        setState({ ...state, zoomLevel: newZoom, panOffset: newPanOffset });
    };

    // 平移处理函数
    const handlePan = (deltaX: number) => {
        // 计算平移边界限制
        const maxPanOffset = 100 * state.zoomLevel; // 最大平移距离与缩放级别相关
        const newOffset = Math.max(-maxPanOffset, Math.min(maxPanOffset, state.panOffset + deltaX));
        // const newOffset = state.panOffset + deltaX
        setState({ ...state, panOffset: newOffset });
    };

    // 重置缩放和平移
    const resetView = () => {
        setState({ ...state, zoomLevel: initialZoom, panOffset: 0 });
    };

    const vaoRef = useRef<WebGLVertexArrayObject | null>(null);
    const vertex_bfRef = useRef<WebGLBuffer | null>(null);
    const uniform_bfRef = useRef<WebGLBuffer | null>(null);
    const instants_bfRef = useRef<WebGLBuffer | null>(null);
    const programRef = useRef<WebGLProgram | null>(null);
    const instants_countRef = useRef<number>(0);

    // 统一的重绘函数，支持临时状态覆盖
    const redraw = useCallback((overrides: RedrawOverrides = {}) => {
        if (!canvasRef.current || !ticksCanvasRef.current) return;

        const rect = ticksCanvasRef.current.getBoundingClientRect();
        if (rect.width <= 0 || rect.height <= 0) return;

        const dpr = window.devicePixelRatio || 1;
        const currentState = stateRef.current;
        const currentProps = propsRef.current;

        drawTicks(
            ticksCanvasRef.current,
            rect.width,
            rect.height,
            dpr,
            overrides.startDate ?? currentProps.startDate,
            overrides.endDate ?? currentProps.endDate,
            overrides.currentDate ?? currentProps.currentDate,
            overrides.zoomLevel ?? currentState.zoomLevel,
            overrides.panOffset ?? currentState.panOffset,
            overrides.customLineTimestamp ?? currentState.customLineTimestamp,
            overrides.isDragging ?? currentState.isDragging
        );
    }, []);

    // 只在特定情况下监听重绘
    useEffect(() => {
        // 避免拖拽时的重复重绘
        const currentState = stateRef.current;
        if ((currentState.isDragging && currentState.isLongPress) || currentState.isPanningTimeline) return;

        // 使用requestAnimationFrame优化重绘性能
        const rafId = requestAnimationFrame(() => {
            redraw();
        });

        return () => {
            cancelAnimationFrame(rafId);
        };
    }, [state.customLineTimestamp, state.zoomLevel, state.panOffset, startDate, endDate, currentDate, redraw]);

    const { radius, d } = calcVersicaUni(boxSize);

    const current_uniforms = useRef<Uniforms>({
        startTimestamp: 0,
        endTimestamp: 0,
        currentTimestamp: 0,
        radius: radius,
        d: d,
        timelineStartX: 0,
        timelineEndX: 0,
        viewportSize: [0, 0],
        zoomLevel: initialZoom,
        panOffset: 0,
    })

    useEffect(() => {
        if (!canvasRef.current || !ticksCanvasRef.current) return;
        const { radius, d } = calcVersicaUni(boxSize);

        const handleMouseClick = (e: MouseEvent) => {
            const rect = ticksCanvasRef.current?.getBoundingClientRect();
            if (!rect) return;
            const mouseX = e.clientX - rect.left;
            const mouseY = e.clientY - rect.top;
            const centerY = rect.height / 2;

            const currentState = stateRef.current;

            // 如果刚刚完成了时间轴拖拽，则不处理点击事件
            // 注意：现在只检查是否已经实际拖拽过，而不是检查isPanningTimeline状态
            if (hasDraggedTimelineRef.current) {
                return;
            }

            const timelineStartX = 40;
            const timelineEndX = rect.width - 40;
            const timelineRange = 20;

            // 检查是否在时间轴区域内点击
            const isInTimelineArea = mouseX >= timelineStartX && mouseX <= timelineEndX &&
                Math.abs(mouseY - centerY) <= timelineRange;

            // 检查是否点击了现有的自定义竖线附近
            let isNearCustomLine = false;
            if (currentState.customLineTimestamp !== null && startDate && endDate) {
                // 根据时间戳计算当前屏幕位置
                const timeRange = endDate.getTime() - startDate.getTime();
                const visibleTimeRange = timeRange / currentState.zoomLevel;
                const timelineWidth = timelineEndX - timelineStartX;
                const timePerPixel = visibleTimeRange / timelineWidth;
                const panTimeOffset = -currentState.panOffset * timePerPixel;
                const originalCenterTime = startDate.getTime() + timeRange / 2;
                const newCenterTime = originalCenterTime + panTimeOffset;
                const visibleStartTime = newCenterTime - visibleTimeRange / 2;

                const timeProgress = (currentState.customLineTimestamp - visibleStartTime) / visibleTimeRange;
                const customLineScreenX = timelineStartX + timeProgress * timelineWidth;

                isNearCustomLine = Math.abs(mouseX - customLineScreenX) <= 10;
            }

            // 只在时间轴区域内点击且不是竖线附近时创建指示器
            if (isInTimelineArea && !isNearCustomLine) {
                // 根据当前的缩放和平移状态计算点击位置对应的时间戳
                if (startDate && endDate) {
                    const timelineWidth = timelineEndX - timelineStartX;
                    const relativeX = mouseX - timelineStartX;
                    const progress = relativeX / timelineWidth;

                    // 基于可见时间窗口计算时间戳
                    const timeRange = endDate.getTime() - startDate.getTime();
                    const visibleTimeRange = timeRange / currentState.zoomLevel;
                    const timePerPixel = visibleTimeRange / timelineWidth;
                    const panTimeOffset = -currentState.panOffset * timePerPixel;
                    const originalCenterTime = startDate.getTime() + timeRange / 2;
                    const newCenterTime = originalCenterTime + panTimeOffset;
                    const visibleStartTime = newCenterTime - visibleTimeRange / 2;

                    const selectedTimestamp = visibleStartTime + progress * visibleTimeRange;

                    setState(prevState => ({
                        ...prevState,
                        customLineTimestamp: selectedTimestamp,
                        isLongPress: false,
                        isDragging: false
                    }));

                    // 通知父组件
                    if (onDateChange) {
                        onDateChange(new Date(selectedTimestamp));
                    }
                }
            }
        }


        // 在useEffect内部定义事件处理函数，确保正确的作用域和清理
        // 鼠标按下处理 - 检测是否点击了自定义竖线，或创建新竖线，或开始拖拽时间轴
        const handleMouseDown = (e: MouseEvent) => {
            const rect = ticksCanvasRef.current?.getBoundingClientRect();
            if (!rect) return;

            const mouseX = e.clientX - rect.left;
            const mouseY = e.clientY - rect.top;
            const centerY = rect.height / 2;

            const currentState = stateRef.current;

            // 定义时间轴区域 - 与drawTicks中的参数保持一致
            const timelineStartX = 40;
            const timelineEndX = rect.width - 40;
            const timelineRange = 20; // 减小范围，让判断更精确


            // 检查是否在时间轴的主要区域内（优先级最高）
            const isInTimelineArea = mouseX >= timelineStartX && mouseX <= timelineEndX &&
                Math.abs(mouseY - centerY) <= timelineRange;

            // 检查是否点击了现有的自定义竖线附近
            let isNearCustomLine = false;
            if (currentState.customLineTimestamp !== null && startDate && endDate) {
                // 根据时间戳计算当前屏幕位置
                const timeRange = endDate.getTime() - startDate.getTime();
                const visibleTimeRange = timeRange / currentState.zoomLevel;
                const timelineWidth = timelineEndX - timelineStartX;
                const timePerPixel = visibleTimeRange / timelineWidth;
                const panTimeOffset = -currentState.panOffset * timePerPixel;
                const originalCenterTime = startDate.getTime() + timeRange / 2;
                const newCenterTime = originalCenterTime + panTimeOffset;
                const visibleStartTime = newCenterTime - visibleTimeRange / 2;

                const timeProgress = (currentState.customLineTimestamp - visibleStartTime) / visibleTimeRange;
                const customLineScreenX = timelineStartX + timeProgress * timelineWidth;

                isNearCustomLine = Math.abs(mouseX - customLineScreenX) <= 10;
            }

            if (isNearCustomLine) {
                // 处理自定义竖线拖拽（长按激活）
                longPressTimerRef.current = setTimeout(() => {
                    setState(prevState => ({ ...prevState, isLongPress: true, isDragging: true }));
                    redraw({ isDragging: true });
                }, 100);
            } else if (isInTimelineArea) {
                // 记录鼠标按下位置，但不立即开启拖拽模式
                // 等待鼠标移动超过阈值时再开启拖拽
                panStartXRef.current = mouseX;
                panStartOffsetRef.current = currentState.panOffset;
                panTempOffsetRef.current = currentState.panOffset;
                hasDraggedTimelineRef.current = false; // 重置拖拽标记
            } else {
                // 不在任何特殊区域，不执行任何操作
                // 移除在时间轴区域外创建竖线的逻辑，因为现在通过click事件处理
            }
        };

        // 鼠标移动处理 - 拖拽自定义竖线或拖拽时间轴
        const handleMouseMove = (e: MouseEvent) => {
            const rect = ticksCanvasRef.current?.getBoundingClientRect();
            if (!rect) return;

            const mouseX = e.clientX - rect.left;
            const mouseY = e.clientY - rect.top;
            const centerY = rect.height / 2;
            const currentState = stateRef.current;

            // 处理指示器拖拽
            if (currentState.isDragging && currentState.isLongPress) {
                // 限制竖线在时间轴范围内
                const startX = 40;
                const endX = rect.width - 40;
                const clampedX = Math.max(startX, Math.min(endX, mouseX));

                // 使用ref存储临时位置，避免频繁状态更新
                dragTempXRef.current = clampedX;

                // 使用requestAnimationFrame优化重绘
                if (animationFrameRef.current) {
                    cancelAnimationFrame(animationFrameRef.current);
                }

                animationFrameRef.current = requestAnimationFrame(() => {
                    if (ticksCanvasRef.current && dragTempXRef.current !== null && startDate && endDate) {
                        const rect = ticksCanvasRef.current.getBoundingClientRect();
                        const timelineStartX = 40;
                        const timelineEndX = rect.width - 40;
                        const timelineWidth = timelineEndX - timelineStartX;
                        const relativeX = dragTempXRef.current - timelineStartX;
                        const progress = relativeX / timelineWidth;

                        // 基于可见时间窗口计算时间戳
                        const timeRange = endDate.getTime() - startDate.getTime();
                        const visibleTimeRange = timeRange / currentState.zoomLevel;
                        const timePerPixel = visibleTimeRange / timelineWidth;
                        const panTimeOffset = -currentState.panOffset * timePerPixel;
                        const originalCenterTime = startDate.getTime() + timeRange / 2;
                        const newCenterTime = originalCenterTime + panTimeOffset;
                        const visibleStartTime = newCenterTime - visibleTimeRange / 2;

                        const dragTimestamp = visibleStartTime + progress * visibleTimeRange;

                        redraw({
                            customLineTimestamp: dragTimestamp,
                            isDragging: true
                        });
                    }
                });
                return;
            }

            // 处理时间轴拖拽
            if (currentState.isPanningTimeline) {
                const deltaX = mouseX - panStartXRef.current;
                const newOffset = panStartOffsetRef.current + deltaX;

                // 如果移动距离超过阈值，标记为已拖拽（使用ref避免频繁状态更新）
                if (Math.abs(deltaX) > 3) {
                    hasDraggedTimelineRef.current = true;
                }

                // 应用边界限制
                const maxPanOffset = 100 * currentState.zoomLevel;
                const clampedOffset = Math.max(-maxPanOffset, Math.min(maxPanOffset, newOffset));

                // 存储临时偏移
                panTempOffsetRef.current = clampedOffset;

                // 直接重绘，不使用requestAnimationFrame以减少延迟
                if (ticksCanvasRef.current) {
                    redraw({
                        panOffset: panTempOffsetRef.current
                    });
                }
                return;
            }

            // 检查是否应该开始时间轴拖拽（移动距离阈值检查）
            if (!currentState.isPanningTimeline && !currentState.isDragging && panStartXRef.current !== 0) {
                const deltaX = mouseX - panStartXRef.current;
                const dragThreshold = 8; // 拖拽阈值：8像素

                // 检查是否在时间轴区域内
                const timelineStartX = 40;
                const timelineEndX = rect.width - 40;
                const timelineRange = 20;
                const isInTimelineArea = mouseX >= timelineStartX && mouseX <= timelineEndX &&
                    Math.abs(mouseY - centerY) <= timelineRange;

                // 只有在时间轴区域内且移动距离超过阈值时才开启拖拽
                if (isInTimelineArea && Math.abs(deltaX) > dragThreshold) {
                    setState(prevState => ({ ...prevState, isPanningTimeline: true }));
                }
            }

            updateCursorStyle();
        };

        // 鼠标抬起处理 - 结束拖拽
        const handleMouseUp = () => {
            const currentState = stateRef.current;

            // 清除长按计时器
            if (longPressTimerRef.current) {
                clearTimeout(longPressTimerRef.current);
                longPressTimerRef.current = null;
            }

            // 取消待处理的动画帧
            if (animationFrameRef.current) {
                cancelAnimationFrame(animationFrameRef.current);
                animationFrameRef.current = null;
            }

            // 处理指示器拖拽结束
            if (currentState.isDragging && currentState.isLongPress && dragTempXRef.current !== null) {
                // 将最终的屏幕坐标转换为时间戳并保存
                if (startDate && endDate && ticksCanvasRef.current) {
                    const rect = ticksCanvasRef.current.getBoundingClientRect();
                    const timelineStartX = 40;
                    const timelineEndX = rect.width - 40;
                    const timelineWidth = timelineEndX - timelineStartX;
                    const relativeX = dragTempXRef.current - timelineStartX;
                    const progress = relativeX / timelineWidth;

                    // 基于可见时间窗口计算时间戳
                    const timeRange = endDate.getTime() - startDate.getTime();
                    const visibleTimeRange = timeRange / currentState.zoomLevel;
                    const timePerPixel = visibleTimeRange / timelineWidth;
                    const panTimeOffset = -currentState.panOffset * timePerPixel;
                    const originalCenterTime = startDate.getTime() + timeRange / 2;
                    const newCenterTime = originalCenterTime + panTimeOffset;
                    const visibleStartTime = newCenterTime - visibleTimeRange / 2;

                    const finalTimestamp = visibleStartTime + progress * visibleTimeRange;

                    setState(prevState => ({
                        ...prevState,
                        customLineTimestamp: finalTimestamp,
                        isDragging: false,
                        isLongPress: false
                    }));
                } else {
                    setState(prevState => ({ ...prevState, isDragging: false, isLongPress: false }));
                }
                dragTempXRef.current = null;
            } else if (currentState.isPanningTimeline) {
                // 处理时间轴拖拽结束
                // 提交临时偏移到真实状态并重置时间轴拖拽状态
                const finalOffset = panTempOffsetRef.current;
                setState(prevState => ({
                    ...prevState,
                    panOffset: finalOffset,
                    isPanningTimeline: false
                }));

                // 立即用最终偏移重绘，确保显示正确
                redraw({
                    panOffset: finalOffset
                });

                // 光标样式由updateCursorStyle统一管理

                // 延迟重置拖拽标记和临时偏移
                setTimeout(() => {
                    hasDraggedTimelineRef.current = false;
                    panTempOffsetRef.current = 0; // 现在可以安全重置了
                }, 50);
            } else {
                // 只重置拖拽状态
                setState(prevState => ({ ...prevState, isDragging: false, isLongPress: false }));
            }

            // 重置拖拽起始位置（重要：避免后续误判）
            panStartXRef.current = 0;
        };

        // 更新光标样式的通用函数
        const updateCursorStyle = () => {
            const currentState = stateRef.current;
            if (!ticksCanvasRef.current) return;

            if (currentState.isPanningTimeline) {
                // 当且仅当正在拖拽时间轴时显示抓取中光标
                ticksCanvasRef.current.style.cursor = 'grabbing';
            } else {
                // 其余所有情况均显示十字光标
                ticksCanvasRef.current.style.cursor = 'crosshair';
            }
        };

        // 鼠标悬停处理 - 动态改变鼠标样式
        const handleMouseOver = (e: MouseEvent) => {
            updateCursorStyle();
        };

        // 鼠标移出处理
        const handleMouseOut = () => {
            // 光标样式由updateCursorStyle统一管理，不需要特殊处理
        };

        // 获取设备像素比例以支持高分屏
        const dpr = window.devicePixelRatio || 1;
        const displayWidth = canvasRef.current.clientWidth;
        const displayHeight = canvasRef.current.clientHeight;

        // 设置WebGL canvas的实际像素尺寸（考虑高分屏）
        const actualWidth = Math.floor(displayWidth * dpr);
        const actualHeight = Math.floor(displayHeight * dpr);

        canvasRef.current.width = actualWidth;
        canvasRef.current.height = actualHeight;

        // 设置CSS显示尺寸
        canvasRef.current.style.width = displayWidth + 'px';
        canvasRef.current.style.height = displayHeight + 'px';

        // 设置刻度线canvas的尺寸
        setupTicksCanvas(ticksCanvasRef.current, displayWidth, displayHeight, dpr);

        // 初始绘制刻度线，确保canvas设置完成后立即显示
        redraw();

        // 更新uniform数据
        current_uniforms.current.viewportSize = [actualWidth, actualHeight];
        current_uniforms.current.radius = radius * dpr; // 调整radius以适应像素密度
        current_uniforms.current.d = d * dpr; // 调整d以适应像素密度
        current_uniforms.current.timelineStartX = 40 * dpr; // 时间轴开始坐标
        current_uniforms.current.timelineEndX = (displayWidth - 40) * dpr; // 时间轴结束坐标
        current_uniforms.current.zoomLevel = state.zoomLevel;
        current_uniforms.current.panOffset = state.panOffset * dpr;

        // 设置时间戳范围
        if (startDate && endDate) {
            current_uniforms.current.startTimestamp = startDate.getTime();
            current_uniforms.current.endTimestamp = endDate.getTime();
        }
        if (currentDate) {
            current_uniforms.current.currentTimestamp = currentDate.getTime();
        }


        const gl = (canvasRef.current.getContext('webgl2', {
            antialias: true,        // 启用抗锯齿
            alpha: true,           // 启用alpha通道以支持透明度
            premultipliedAlpha: false, // 不使用预乘alpha
            depth: false,          // 不需要深度缓冲
            stencil: false,        // 不需要模板缓冲
            preserveDrawingBuffer: false // 不保留绘制缓冲区
        }) as WebGL2RenderingContext);
        if (!gl) {
            console.error('WebGL2 not supported');
            return;
        }

        const program = createProgram(gl);
        if (!program) {
            console.error('Failed to create program');
            return;
        }

        // 绑定uniform buffer到着色器程序
        const uniformBlockIndex = gl.getUniformBlockIndex(program, 'Uniforms');
        if (uniformBlockIndex !== gl.INVALID_INDEX) {
            gl.uniformBlockBinding(program, uniformBlockIndex, 0);
        }

        const vao = gl.createVertexArray();

        if (!vao) {
            console.error('Failed to create vertex array');
            return;
        }
        gl.bindVertexArray(vao);

        const vertex_bf = defaultVb(gl);
        const { buffer: instants_bf, count: actualInstanceCount } = createVesicaInstances(gl, actualVesicaData, actualWidth, actualHeight, dpr);
        const uniform_bf = defaultUb(gl, current_uniforms.current);

        gl.bindVertexArray(null);
        gl.bindBuffer(gl.ARRAY_BUFFER, null);
        gl.bindBuffer(gl.UNIFORM_BUFFER, null);

        vaoRef.current = vao;
        vertex_bfRef.current = vertex_bf;
        uniform_bfRef.current = uniform_bf;
        instants_bfRef.current = instants_bf;
        programRef.current = program;
        instants_countRef.current = actualInstanceCount; // 使用实际生成的实例数量

        function render() {
            gl.clearColor(0, 0, 0, 0); // 深灰背景，便于看到刻度
            gl.clear(gl.COLOR_BUFFER_BIT);

            gl.useProgram(program);
            gl.bindVertexArray(vaoRef.current);

            // 绑定uniform buffer
            gl.bindBufferBase(gl.UNIFORM_BUFFER, 0, uniform_bfRef.current);

            gl.drawArraysInstanced(gl.TRIANGLE_STRIP, 0, 4, instants_countRef.current);
            gl.bindVertexArray(null);
        }

        function updateUniforms(uniforms: Uniforms) {
            gl.bindBuffer(gl.UNIFORM_BUFFER, uniform_bfRef.current!);
            const uniformData = new Float32Array([
                uniforms.startTimestamp,
                uniforms.endTimestamp,
                uniforms.currentTimestamp,
                uniforms.radius,
                uniforms.d,
                uniforms.timelineStartX,
                uniforms.timelineEndX,
                0.0,  // padding - 填充以对齐到8字节边界
                uniforms.viewportSize[0],
                uniforms.viewportSize[1],
                uniforms.zoomLevel,
                uniforms.panOffset
            ]);
            gl.bufferData(gl.UNIFORM_BUFFER, uniformData, gl.DYNAMIC_DRAW);
        }


        // TODO: 可以通过props传入自定义的时间轴刻度数据
        // 或使用useImperativeHandle暴露更新方法

        // 初始化uniform数据并渲染
        updateUniforms(current_uniforms.current);
        gl.viewport(0, 0, actualWidth, actualHeight);
        render();

        // 鼠标滚轮缩放和平移
        const handleWheel = (e: WheelEvent) => {
            e.preventDefault();
            const rect = ticksCanvasRef.current?.getBoundingClientRect();
            if (!rect) return;

            const mouseX = e.clientX - rect.left;
            const mouseY = e.clientY - rect.top;
            const centerY = rect.height / 2;

            // 只在时间轴区域内滚动时才处理
            const timelineStartX = 40;
            const timelineEndX = rect.width - 40;
            const timelineRange = 30; // 扩大一点范围

            const isInTimelineArea = mouseX >= timelineStartX && mouseX <= timelineEndX &&
                Math.abs(mouseY - centerY) <= timelineRange;

            if (isInTimelineArea) {
                // 设置阈值，避免微小滚动触发操作
                const deltaThreshold = 3;
                const deltaX = e.deltaX;
                const deltaY = e.deltaY;

                // 判断主要滚动方向和是否超过阈值
                if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > deltaThreshold) {
                    // 水平滚动：平移操作
                    // 反转方向并增加速度，使滚动更跟手
                    handlePan(-deltaX * 2); // 反转方向，增加速度倍数
                } else if (Math.abs(deltaY) > Math.abs(deltaX) && Math.abs(deltaY) > deltaThreshold) {
                    // 垂直滚动：缩放操作
                    handleZoom(-deltaY, mouseX);
                }
            }
        };

        // 触摸缩放和平移
        let lastTouchDistance = 0;
        let lastTouchX = 0;
        let isPanning = false;

        const handleTouchStart = (e: TouchEvent) => {
            if (e.touches.length === 2) {
                // 双指缩放
                const dx = e.touches[0].clientX - e.touches[1].clientX;
                const dy = e.touches[0].clientY - e.touches[1].clientY;
                lastTouchDistance = Math.sqrt(dx * dx + dy * dy);
            } else if (e.touches.length === 1) {
                // 单指平移
                lastTouchX = e.touches[0].clientX;
                isPanning = true;
            }
        };

        const handleTouchMove = (e: TouchEvent) => {
            e.preventDefault();
            if (e.touches.length === 2) {
                // 双指缩放
                const dx = e.touches[0].clientX - e.touches[1].clientX;
                const dy = e.touches[0].clientY - e.touches[1].clientY;
                const distance = Math.sqrt(dx * dx + dy * dy);

                if (lastTouchDistance > 0) {
                    const scale = distance / lastTouchDistance;
                    const delta = scale > 1 ? 1 : -1;
                    handleZoom(delta * 50);
                }
                lastTouchDistance = distance;
            } else if (e.touches.length === 1 && isPanning) {
                // 单指平移
                const deltaX = e.touches[0].clientX - lastTouchX;
                handlePan(deltaX);
                lastTouchX = e.touches[0].clientX;
            }
        };

        const handleTouchEnd = () => {
            lastTouchDistance = 0;
            isPanning = false;
        };

        // 双击重置
        const handleDoubleClick = () => {
            resetView();
        };

        ticksCanvasRef.current?.addEventListener('wheel', handleWheel, { passive: false });
        ticksCanvasRef.current?.addEventListener('touchstart', handleTouchStart);
        ticksCanvasRef.current?.addEventListener('touchmove', handleTouchMove, { passive: false });
        ticksCanvasRef.current?.addEventListener('touchend', handleTouchEnd);
        ticksCanvasRef.current?.addEventListener('dblclick', handleDoubleClick);
        ticksCanvasRef.current?.addEventListener('mouseover', handleMouseOver);
        ticksCanvasRef.current?.addEventListener('mouseout', handleMouseOut);

        // 添加自定义竖线相关的事件监听器
        ticksCanvasRef.current?.addEventListener('mousedown', handleMouseDown);
        ticksCanvasRef.current?.addEventListener('mousemove', handleMouseMove);
        ticksCanvasRef.current?.addEventListener('click', handleMouseClick);
        ticksCanvasRef.current?.addEventListener('mouseup', handleMouseUp);
        // 添加全局鼠标抬起事件，防止鼠标移出canvas后拖拽卡住
        document.addEventListener('mouseup', handleMouseUp);

        // 使用ResizeObserver监听canvas尺寸变化
        const resizeObserver = new ResizeObserver((entries) => {
            for (const entry of entries) {
                const { width: new_width, height: new_height } = entry.contentRect;

                // 获取设备像素比例以支持高分屏
                const dpr = window.devicePixelRatio || 1;
                const actualWidth = Math.floor(new_width * dpr);
                const actualHeight = Math.floor(new_height * dpr);

                // 更新canvas的实际像素尺寸
                canvasRef.current!.width = actualWidth;
                canvasRef.current!.height = actualHeight;

                // 设置CSS显示尺寸
                canvasRef.current!.style.width = new_width + 'px';
                canvasRef.current!.style.height = new_height + 'px';

                // 更新刻度线canvas的尺寸
                setupTicksCanvas(ticksCanvasRef.current!, new_width, new_height, dpr);

                // ResizeObserver中需要立即重绘，因为setupTicksCanvas会清空canvas
                redraw();

                // 更新uniform数据
                current_uniforms.current.viewportSize = [actualWidth, actualHeight];
                current_uniforms.current.radius = radius * dpr; // 调整radius以适应像素密度
                current_uniforms.current.d = d * dpr; // 调整d以适应像素密度
                current_uniforms.current.timelineStartX = 40 * dpr; // 时间轴开始坐标
                current_uniforms.current.timelineEndX = (new_width - 40) * dpr; // 时间轴结束坐标
                current_uniforms.current.zoomLevel = stateRef.current.zoomLevel;
                current_uniforms.current.panOffset = stateRef.current.panOffset * dpr;

                // 重新生成实例数据以适应新的canvas尺寸
                const { buffer: new_instants_bf, count: new_count } = createVesicaInstances(gl, actualVesicaData, actualWidth, actualHeight, dpr);

                // 更新实例buffer引用和数量
                if (instants_bfRef.current) {
                    gl.deleteBuffer(instants_bfRef.current);
                }
                instants_bfRef.current = new_instants_bf;
                instants_countRef.current = new_count;

                updateUniforms(current_uniforms.current);
                gl.viewport(0, 0, actualWidth, actualHeight);
                render();
            }
        });

        resizeObserver.observe(canvasRef.current!);

        return () => {
            // 移除事件监听器
            ticksCanvasRef.current?.removeEventListener('wheel', handleWheel);
            ticksCanvasRef.current?.removeEventListener('touchstart', handleTouchStart);
            ticksCanvasRef.current?.removeEventListener('touchmove', handleTouchMove);
            ticksCanvasRef.current?.removeEventListener('touchend', handleTouchEnd);
            ticksCanvasRef.current?.removeEventListener('dblclick', handleDoubleClick);
            ticksCanvasRef.current?.removeEventListener('mouseover', handleMouseOver);
            ticksCanvasRef.current?.removeEventListener('mouseout', handleMouseOut);

            // 移除自定义竖线相关的事件监听器
            ticksCanvasRef.current?.removeEventListener('mousedown', handleMouseDown);
            ticksCanvasRef.current?.removeEventListener('mousemove', handleMouseMove);
            ticksCanvasRef.current?.removeEventListener('click', handleMouseClick);
            ticksCanvasRef.current?.removeEventListener('mouseup', handleMouseUp);
            document.removeEventListener('mouseup', handleMouseUp);

            // 清理长按计时器
            if (longPressTimerRef.current) {
                clearTimeout(longPressTimerRef.current);
            }

            // 清理动画帧
            if (animationFrameRef.current) {
                cancelAnimationFrame(animationFrameRef.current);
            }

            // 重置临时状态（不需要调用setState，因为组件即将卸载或重新初始化）
            panTempOffsetRef.current = 0;

            resizeObserver.disconnect();

            // 清理WebGL资源
            if (vaoRef.current) gl.deleteVertexArray(vaoRef.current);
            if (vertex_bfRef.current) gl.deleteBuffer(vertex_bfRef.current);
            if (uniform_bfRef.current) gl.deleteBuffer(uniform_bfRef.current);
            if (instants_bfRef.current) gl.deleteBuffer(instants_bfRef.current);
            if (programRef.current) gl.deleteProgram(programRef.current);
        }
    }, [boxSize, actualVesicaData]);

    // 监听状态变化，更新uniform数据并重新渲染
    useEffect(() => {
        if (!programRef.current || !uniform_bfRef.current) return;

        // 更新缩放和平移相关的uniform
        current_uniforms.current.zoomLevel = state.zoomLevel;
        current_uniforms.current.panOffset = state.panOffset * (window.devicePixelRatio || 1);

        // 更新时间戳数据
        if (startDate && endDate) {
            current_uniforms.current.startTimestamp = startDate.getTime();
            current_uniforms.current.endTimestamp = endDate.getTime();
        }
        if (currentDate) {
            current_uniforms.current.currentTimestamp = currentDate.getTime();
        }

        // 获取WebGL上下文并更新uniform
        const canvas = canvasRef.current;
        if (canvas) {
            const gl = canvas.getContext('webgl2') as WebGL2RenderingContext;
            if (gl) {
                const program = programRef.current;
                gl.useProgram(program);

                // 更新uniform数据
                gl.bindBuffer(gl.UNIFORM_BUFFER, uniform_bfRef.current);
                const uniformData = new Float32Array([
                    current_uniforms.current.startTimestamp,
                    current_uniforms.current.endTimestamp,
                    current_uniforms.current.currentTimestamp,
                    current_uniforms.current.radius,
                    current_uniforms.current.d,
                    current_uniforms.current.timelineStartX,
                    current_uniforms.current.timelineEndX,
                    0.0,  // padding
                    current_uniforms.current.viewportSize[0],
                    current_uniforms.current.viewportSize[1],
                    current_uniforms.current.zoomLevel,
                    current_uniforms.current.panOffset
                ]);
                gl.bufferData(gl.UNIFORM_BUFFER, uniformData, gl.DYNAMIC_DRAW);

                // 重新渲染
                gl.clearColor(0, 0, 0, 0);
                gl.clear(gl.COLOR_BUFFER_BIT);
                gl.bindVertexArray(vaoRef.current);
                gl.bindBufferBase(gl.UNIFORM_BUFFER, 0, uniform_bfRef.current);
                gl.drawArraysInstanced(gl.TRIANGLE_STRIP, 0, 4, instants_countRef.current);
                gl.bindVertexArray(null);
            }
        }
    }, [state.zoomLevel, state.panOffset, startDate, endDate, currentDate]);

    return (
        <div className={cn(props.className, "w-full h-12 flex flex-row")}>
            <div className="h-full flex flex-row items-center px-3 gap-2" style={{ boxShadow: '8px 0 24px rgba(0, 0, 0, 0.15), 4px 0 12px rgba(0, 0, 0, 0.1)' }}>
                <Button variant="secondary" size="icon" className="size-5">
                    <ChevronLeft size={10} />
                </Button>

                <Button variant="secondary" size="icon" className="size-5" onClick={() => togglePlay()}>
                    {isPlaying ? <Pause size={10} /> : <Play size={10} />}
                </Button>

                <Button variant="secondary" size="icon" className="size-5" onClick={() => forward()}>
                    <ChevronRight size={10} />
                </Button>

                {/* <SelectDemo /> */}

            </div>
            <div className={cn("relative", "w-full h-full")}>
                <canvas ref={canvasRef} className="w-full h-full absolute inset-0" />
                <canvas
                    ref={ticksCanvasRef}
                    className="w-full h-full absolute inset-0 select-none"
                    style={{ touchAction: 'manipulation' }}
                />
            </div>
        </div>

    );
}

function createProgram(gl: WebGL2RenderingContext) {
    const [vs, fs] = createShader(gl)!;
    const prog = gl.createProgram();

    gl.attachShader(prog, vs);
    gl.attachShader(prog, fs);
    gl.linkProgram(prog);

    if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {
        console.error('Failed to link program');
        console.error(gl.getProgramInfoLog(prog));
        // 清理着色器对象
        gl.deleteShader(vs);
        gl.deleteShader(fs);
        return null;
    }

    // 程序链接成功后，删除着色器对象以释放内存
    gl.deleteShader(vs);
    gl.deleteShader(fs);

    return prog;
}

function createShader(gl: WebGL2RenderingContext) {

    const vs = gl.createShader(gl.VERTEX_SHADER);
    if (!vs) {
        console.error('Failed to create vertex shader');
        return null;
    }
    gl.shaderSource(vs, vsSource);
    gl.compileShader(vs);

    if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) {
        console.error('Failed to compile vertex shader:', gl.getShaderInfoLog(vs));
        gl.deleteShader(vs);
        return null;
    }

    const fs = gl.createShader(gl.FRAGMENT_SHADER);
    if (!fs) {
        console.error('Failed to create fragment shader');
        gl.deleteShader(vs);
        return null;
    }
    gl.shaderSource(fs, fsSource);
    gl.compileShader(fs);

    if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) {
        console.error('Failed to compile fragment shader:', gl.getShaderInfoLog(fs));
        gl.deleteShader(vs);
        gl.deleteShader(fs);
        return null;
    }

    return [vs, fs] as [WebGLShader, WebGLShader];
}

function defaultVb(gl: WebGL2RenderingContext) {

    const plane = new Float32Array([
        -1, -1,
        -1, 1,
        1, -1,
        1, 1,
    ]);

    const vertex_bf = gl.createBuffer()!;

    gl.bindBuffer(gl.ARRAY_BUFFER, vertex_bf);
    gl.bufferData(gl.ARRAY_BUFFER, plane, gl.STATIC_DRAW);

    gl.enableVertexAttribArray(0);
    gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
    gl.vertexAttribDivisor(0, 0)

    return vertex_bf;
}

function defaultUb(gl: WebGL2RenderingContext, uniforms: Uniforms) {
    const ub = gl.createBuffer()!;
    gl.bindBuffer(gl.UNIFORM_BUFFER, ub);

    // std140布局：需要添加填充以正确对齐
    const uniformData = new Float32Array([
        uniforms.startTimestamp,
        uniforms.endTimestamp,
        uniforms.currentTimestamp,
        uniforms.radius,
        uniforms.d,
        uniforms.timelineStartX,
        uniforms.timelineEndX,
        0.0,  // padding - 填充以对齐到8字节边界
        uniforms.viewportSize[0],
        uniforms.viewportSize[1],
        uniforms.zoomLevel,
        uniforms.panOffset
    ]);

    gl.bufferData(gl.UNIFORM_BUFFER, uniformData, gl.DYNAMIC_DRAW);
    return ub;
}

// 时间轴刻度生成函数
function generateTimelineMarks(startX: number, y: number, interval: number, count: number): Instants[] {
    const marks = [];
    for (let i = 0; i < count; i++) {
        marks.push({
            position: new Float32Array([startX + i * interval, y]),
            color: new Float32Array([0.8, 0.8, 0.8, 1])  // 统一的灰色刻度
        });
    }
    return marks;
}

function createVesicaInstances(
    gl: WebGL2RenderingContext,
    vesicaData: VesicaDataPoint[],
    canvasWidth: number,
    canvasHeight: number,
    dpr: number
): { buffer: WebGLBuffer, count: number } {

    const centerY = Math.floor(canvasHeight * 0.5); // 垂直居中
    const instants: Instants[] = [];

    // 为每个时间戳数据点创建一个 vesica 实例
    // 位置信息将在着色器中根据时间戳计算，这里只存储时间戳作为position.x
    for (const dataPoint of vesicaData) {
        const defaultColor = [1.0, 1.0, 1.0, 1.0]; // 默认白色
        const color = dataPoint.color || defaultColor;

        instants.push({
            position: new Float32Array([dataPoint.timestamp, centerY]), // x存储时间戳，y存储屏幕Y坐标
            color: new Float32Array(color)
        });
    }

    const instants_bf = gl.createBuffer()!;

    gl.bindBuffer(gl.ARRAY_BUFFER, instants_bf);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(instants.flatMap(i => [...i.position, ...i.color])), gl.DYNAMIC_DRAW);

    gl.enableVertexAttribArray(1);
    gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 24, 0); // 6 floats * 4 bytes = 24 bytes stride
    gl.vertexAttribDivisor(1, 1);

    gl.enableVertexAttribArray(2);
    gl.vertexAttribPointer(2, 4, gl.FLOAT, false, 24, 8); // 2 floats * 4 bytes = 8 bytes offset
    gl.vertexAttribDivisor(2, 1);

    return { buffer: instants_bf, count: instants.length };
}

function calcVersicaUni(box_size: [number, number]) {
    const [w, h] = [box_size[0], box_size[1]];

    // 正确的vesica参数：
    // radius: 每个圆的半径，应该稍大于高度的一半以包含整个形状
    // d: 两个圆心之间的距离，必须 < 2*radius
    const radius = Math.max(w * 0.6, h * 0.6); // 确保能包含形状
    const d = Math.min(w * 0.4, radius * 1.5);  // 确保 d < 2*radius

    return {
        radius,
        d,
    }
}

function setupTicksCanvas(canvas: HTMLCanvasElement, width: number, height: number, dpr: number) {
    // 设置canvas的实际像素尺寸（考虑高分屏）
    const actualWidth = Math.floor(width * dpr);
    const actualHeight = Math.floor(height * dpr);
    canvas.width = actualWidth;
    canvas.height = actualHeight;

    // 设置CSS显示尺寸
    canvas.style.width = width + 'px';
    canvas.style.height = height + 'px';

    // 触发重绘（通过更新一个状态来触发useEffect）
    // 这里我们不需要手动触发，因为canvas尺寸变化会自然触发重绘
}



function levelInfo(level: number) {
    // 根据缩放级别确定时间轴级别
    if (level >= 6.0) {
        // 日视角：主刻度为小时，子刻度为分钟
        return {
            level: 'day',
            majorStep: 3600000, // 1小时 = 3600000ms
            minorStep: 600000,  // 10分钟 = 600000ms，在1小时内有6个子刻度
            majorTickHeight: 8,
            minorTickHeight: 4,
            showMinorTicks: true,
            majorLabelFormat: (date: Date) => date.toLocaleTimeString('zh-CN', {
                hour: '2-digit'
            }),
            minorLabelFormat: (date: Date) => date.toLocaleTimeString('zh-CN', {
                minute: '2-digit'
            })
        };
    } else {
        // 月视角：主刻度为日期，子刻度为小时
        return {
            level: 'month',
            majorStep: 86400000, // 1天 = 86400000ms
            minorStep: 7200000,  // 2小时 = 7200000ms
            majorTickHeight: 7,
            minorTickHeight: 3,
            showMinorTicks: level > 1.2, // 缩放级别大于1.2时显示子刻度
            majorLabelFormat: (date: Date) => date.toLocaleDateString('zh-CN', {
                month: 'short',
                day: 'numeric'
            }),
            minorLabelFormat: (date: Date) => date.toLocaleTimeString('zh-CN', {
                hour: '2-digit'
            })
        };
    }
}



function drawTicks(
    canvas: HTMLCanvasElement,
    width: number,
    height: number,
    dpr: number,
    startDate?: Date,
    endDate?: Date,
    currentDate?: Date,
    zoomLevel: number = 1,
    panOffset: number = 0,
    customLineTimestamp?: number | null,
    isDragging?: boolean
) {
    const ctx = canvas.getContext('2d', {
        alpha: true,
        antialias: true,
    }) as CanvasRenderingContext2D;

    // 保存当前context状态
    ctx.save();

    // 重置变换矩阵并缩放以适应高分屏
    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);

    // 清除canvas
    ctx.clearRect(0, 0, width, height);

    // 时间轴参数
    const centerY = height / 2;
    const startX = 40; // 左边距
    const endX = width - 40; // 右边距
    const timelineWidth = endX - startX;

    // 获取当前级别信息
    const levelConfig = levelInfo(zoomLevel);
    const {
        level,
        majorStep,
        minorStep,
        majorTickHeight,
        minorTickHeight,
        showMinorTicks,
        majorLabelFormat,
        minorLabelFormat
    } = levelConfig;

    // 计算时间范围
    let timeRange = 0;
    if (startDate && endDate) {
        timeRange = endDate.getTime() - startDate.getTime();
    }

    // 计算可见时间窗口（考虑缩放和平移）
    let visibleStartTime = startDate ? startDate.getTime() : 0;
    let visibleEndTime = endDate ? endDate.getTime() : 0;

    if (startDate && endDate) {
        // 缩放改变可见时间范围
        const visibleTimeRange = timeRange / zoomLevel;

        // 平移改变可见时间窗口的中心点
        const timePerPixel = visibleTimeRange / timelineWidth;
        const panTimeOffset = -panOffset * timePerPixel;

        // 计算可见窗口的中心时间
        const originalCenterTime = startDate.getTime() + timeRange / 2;
        const newCenterTime = originalCenterTime + panTimeOffset;

        // 基于缩放后的时间范围和新的中心点计算可见窗口
        visibleStartTime = newCenterTime - visibleTimeRange / 2;
        visibleEndTime = newCenterTime + visibleTimeRange / 2;
    }

    ctx.fillStyle = '#111';
    ctx.fillRect(0, 0, width, 16);

    // 绘制自定义竖线（如果存在）
    if (customLineTimestamp !== null && customLineTimestamp !== undefined && startDate && endDate) {
        // 根据时间戳计算屏幕位置
        const timeProgress = (customLineTimestamp - visibleStartTime) / (visibleEndTime - visibleStartTime);
        const customLineX = startX + timeProgress * timelineWidth;

        // 只在可见区域内绘制
        if (customLineX >= startX - 20 && customLineX <= endX + 20) {
            ctx.strokeStyle = isDragging ? '#ff6666' : '#ff4444'; // 拖拽时加粗颜色
            ctx.lineWidth = isDragging ? 4 : 2; // 拖拽时加粗线条
            ctx.beginPath();
            ctx.moveTo(customLineX, centerY - 20);
            ctx.lineTo(customLineX, centerY + 20);
            ctx.stroke();

            // 绘制上方的三角形指示器
            ctx.fillStyle = isDragging ? '#ff6666' : '#ff4444';
            ctx.beginPath();
            const triangleSize = 6;
            const triangleY = 7; // 在时间轴顶部
            ctx.moveTo(customLineX, triangleY);
            ctx.lineTo(customLineX - triangleSize, triangleY - triangleSize);
            ctx.lineTo(customLineX + triangleSize, triangleY - triangleSize);
            ctx.closePath();
            ctx.fill();

            // 绘制自定义竖线标签
            ctx.fillStyle = isDragging ? '#ff6666' : '#ff4444';
            ctx.font = 'bold 10px Arial';
            ctx.textBaseline = 'bottom';
            const tickTime = new Date(customLineTimestamp);
            const label = majorLabelFormat(tickTime);
            ctx.fillText(label, customLineX, centerY - 22);
        }
    }

    // 绘制子刻度（如果启用）
    if (showMinorTicks && startDate && endDate) {
        ctx.strokeStyle = '#ccc';
        ctx.lineWidth = 1;

        // 更精确的子刻度时间范围计算
        const startTickTime = Math.floor(visibleStartTime / minorStep) * minorStep;
        const endTickTime = Math.ceil(visibleEndTime / minorStep) * minorStep;

        // 根据缩放级别动态调整子刻度间距
        const minMinorTickSpacing = zoomLevel >= 8 ? 6 : zoomLevel >= 6 ? 8 : 12;

        let lastMinorTickX = -minMinorTickSpacing;
        let minorTickCount = 0; // 添加计数器用于调试

        for (let tickTime = startTickTime; tickTime <= endTickTime; tickTime += minorStep) {
            // 计算这个时间点在屏幕上的位置
            const timeProgress = (tickTime - visibleStartTime) / (visibleEndTime - visibleStartTime);
            const x = startX + timeProgress * timelineWidth;

            // 只绘制在可见区域内的刻度，扩大边界以避免边缘漏画
            if (x < startX - 20 || x > endX + 20) continue;

            // 跳过主刻度位置 - 使用容差来处理浮点数精度问题
            const timeDiffFromMajor = tickTime % majorStep;
            const tolerance = 1000; // 减小容差到1秒，避免误判
            const isAtMajorTick = Math.abs(timeDiffFromMajor) < tolerance ||
                Math.abs(timeDiffFromMajor - majorStep) < tolerance;

            if (isAtMajorTick) continue;

            // 检查子刻度间距，避免过于密集
            const spacingFromLast = x - lastMinorTickX;
            if (spacingFromLast >= minMinorTickSpacing) {
                // 绘制子刻度线
                ctx.beginPath();
                ctx.moveTo(x, 16 - minorTickHeight);
                ctx.lineTo(x, 16);
                ctx.stroke();
                lastMinorTickX = x;
                minorTickCount++;
            }
        }

        // 仅在调试模式下输出错误信息
        if (minorTickCount === 0 && showMinorTicks && zoomLevel >= 6) {
            console.warn(`子刻度绘制异常: 缩放级别${zoomLevel.toFixed(1)}, 未绘制任何子刻度`);
        }
    }

    // 绘制主刻度
    if (startDate && endDate) {
        ctx.strokeStyle = '#666';
        ctx.lineWidth = 1.5;
        ctx.font = '10px Arial';
        ctx.fillStyle = '#666';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'top';

        // 基于可见时间窗口计算刻度
        const startTickTime = Math.floor(visibleStartTime / majorStep) * majorStep;
        const endTickTime = visibleEndTime + majorStep;

        // 计算文字间距，避免重叠
        const minLabelSpacing = 60; // 最小标签间距（像素）
        let lastLabelX = -minLabelSpacing; // 上一个标签的位置

        for (let tickTime = startTickTime; tickTime <= endTickTime; tickTime += majorStep) {
            // 计算这个时间点在屏幕上的位置
            const timeProgress = (tickTime - visibleStartTime) / (visibleEndTime - visibleStartTime);
            const x = startX + timeProgress * timelineWidth;

            // 只绘制在可见区域内的刻度
            if (x < startX - 50 || x > endX + 50) continue;

            // 绘制主刻度线
            ctx.beginPath();
            ctx.moveTo(x, 16 - majorTickHeight);
            ctx.lineTo(x, 16);
            ctx.stroke();

            // 检查文字间距，避免重叠
            if (x - lastLabelX >= minLabelSpacing) {
                // 绘制时间标签
                const tickDate = new Date(tickTime);
                const label = majorLabelFormat(tickDate);
                ctx.fillText(label, x, 16 - majorTickHeight / 2 + 4);
                lastLabelX = x;
            }
        }
    }

    // 绘制当前时间指示器
    if (currentDate && startDate && endDate) {
        // 计算当前时间在可见时间窗口中的位置
        const currentTime = currentDate.getTime();
        const timeProgress = (currentTime - visibleStartTime) / (visibleEndTime - visibleStartTime);
        const currentX = startX + timeProgress * timelineWidth;

        if (currentX >= startX - 20 && currentX <= endX + 20) {
            // 绘制当前时间线
            ctx.strokeStyle = '#ff4444';
            ctx.lineWidth = 3;
            ctx.beginPath();
            ctx.moveTo(currentX, centerY - 20);
            ctx.lineTo(currentX, centerY + 20);
            ctx.stroke();

            // 绘制上方的三角形指示器
            ctx.fillStyle = '#ff4444';
            ctx.beginPath();
            const triangleSize = 6;
            const triangleY = 16; // 在时间轴顶部
            ctx.moveTo(currentX, triangleY);
            ctx.lineTo(currentX - triangleSize, triangleY - triangleSize);
            ctx.lineTo(currentX + triangleSize, triangleY - triangleSize);
            ctx.closePath();
            ctx.fill();

            // 绘制当前时间标签
            ctx.fillStyle = '#ff4444';
            ctx.font = 'bold 10px Arial';
            ctx.textBaseline = 'bottom';
            const currentLabel = majorLabelFormat(currentDate);
            ctx.fillText(currentLabel, currentX, centerY - 22);
        }
    }

    ctx.restore();
}