import React, { useState, useCallback, useEffect } from 'react';
import { Target, PlusCircle, MinusCircle, SquareDashed, Sparkles, SendToBack, Undo, Redo, Loader2, XCircle, Trash2 } from 'lucide-react';
import { cn } from '../lib/utils';
import { Stage, Layer, Image as KonvaImage, Circle, Path, Group, Rect } from 'react-konva';
import useImage from 'use-image';
import { OntologyInspector } from './OntologyInspector';
import { SAM2_MODEL_OPTIONS, useStore, type Mask } from '../store/useStore';
import { getAiModelStatus, predictMask, type AiRuntimeStatus } from '../lib/api';

interface AISegmentationProps {
    onSendToWorkspace: () => void;
}

type PromptPoint = { x: number; y: number; type: 'pos' | 'neg' };
type PromptBox = { x1: number; y1: number; x2: number; y2: number };
type ToolHint = { title: string; body: string };

export function AISegmentation({ onSendToWorkspace }: AISegmentationProps) {
    const storeActiveTool = useStore((state) => state.activeTool);
    const setActiveTool = useStore((state) => state.setActiveTool);
    const masks = useStore((state) => state.masks);
    const setMasks = useStore((state) => state.setMasks);
    const selectedMaskIds = useStore((state) => state.selectedMaskIds);
    const setSelectedMaskIds = useStore((state) => state.setSelectedMaskIds);
    const maskHistory = useStore((state) => state.maskHistory);
    const maskFuture = useStore((state) => state.maskFuture);
    const undoMasks = useStore((state) => state.undoMasks);
    const redoMasks = useStore((state) => state.redoMasks);
    const frames = useStore((state) => state.frames);
    const currentFrameIndex = useStore((state) => state.currentFrameIndex);
    const aiModel = useStore((state) => state.aiModel);
    const setAiModel = useStore((state) => state.setAiModel);
    const activeTemplateId = useStore((state) => state.activeTemplateId);
    const activeClass = useStore((state) => state.activeClass);

    const [modelStatus, setModelStatus] = useState<AiRuntimeStatus | null>(null);
    const [autoDeleteBg, setAutoDeleteBg] = useState(true);
    const [cropMode, setCropMode] = useState(false);
    const [maskOpacity, setMaskOpacity] = useState(72);
    const [isInferencing, setIsInferencing] = useState(false);
    const [inferenceMessage, setInferenceMessage] = useState('');
    const [aiMaskIds, setAiMaskIds] = useState<string[]>([]);
    
    // Canvas state
    const [scale, setScale] = useState(1);
    const [position, setPosition] = useState({ x: 0, y: 0 });
    const [points, setPoints] = useState<PromptPoint[]>([]);
    const [promptBox, setPromptBox] = useState<PromptBox | null>(null);
    const [boxStart, setBoxStart] = useState<{ x: number; y: number } | null>(null);
    const [boxCurrent, setBoxCurrent] = useState<{ x: number; y: number } | null>(null);
    const [cursorPos, setCursorPos] = useState({ x: 0, y: 0 });
    const currentFrame = frames[currentFrameIndex] || null;
    const [image] = useImage(currentFrame?.url || '');
    const aiMaskIdSet = new Set(aiMaskIds);
    const frameMasks = currentFrame
      ? masks.filter((mask) => mask.frameId === currentFrame.id && aiMaskIdSet.has(mask.id))
      : masks.filter((mask) => aiMaskIdSet.has(mask.id));
    const selectedModelStatus = modelStatus?.models.find((model) => model.id === aiModel);
    const modelCanInfer = selectedModelStatus?.available ?? true;

    const effectiveTool = storeActiveTool;
    const toolHint = React.useMemo<ToolHint | null>(() => {
      if (!currentFrame) return null;
      if (effectiveTool === 'point_pos') {
        return {
          title: '正向选点',
          body: '点击目标内部添加正向点；点击已有提示点可删除。完成提示后点击“执行高精度语义分割”。',
        };
      }
      if (effectiveTool === 'point_neg') {
        return {
          title: '反向选点',
          body: '点击不应包含的区域添加反向点；可和框选/正向点一起使用来细化结果。',
        };
      }
      if (effectiveTool === 'box_select') {
        return {
          title: promptBox ? '边界框已建立' : '边界框选',
          body: promptBox
            ? '当前框会随推理一起发送；也可以继续添加正向/反向点细化。重新拖拽会替换框。'
            : '按住并拖拽建立框选区域，松开后保留框，再点击“执行高精度语义分割”。',
        };
      }
      if (effectiveTool === 'move') {
        return { title: '视口控制', body: '拖拽移动画布，滚轮缩放；切回正向/反向点或框选后继续放置提示。' };
      }
      return null;
    }, [currentFrame, effectiveTool, promptBox]);

    const boxRect = React.useMemo(() => {
      const activeBox = boxStart && boxCurrent
        ? {
          x1: Math.min(boxStart.x, boxCurrent.x),
          y1: Math.min(boxStart.y, boxCurrent.y),
          x2: Math.max(boxStart.x, boxCurrent.x),
          y2: Math.max(boxStart.y, boxCurrent.y),
        }
        : promptBox;
      if (!activeBox) return null;
      return {
        x: activeBox.x1,
        y: activeBox.y1,
        width: activeBox.x2 - activeBox.x1,
        height: activeBox.y2 - activeBox.y1,
      };
    }, [boxCurrent, boxStart, promptBox]);

    useEffect(() => {
      let cancelled = false;
      getAiModelStatus(aiModel)
        .then((status) => {
          if (!cancelled) setModelStatus(status);
        })
        .catch(() => {
          if (!cancelled) setModelStatus(null);
        });
      return () => {
        cancelled = true;
      };
    }, [aiModel]);

    useEffect(() => {
      const visibleIds = new Set(frameMasks.map((mask) => mask.id));
      const nextSelectedMaskIds = selectedMaskIds.filter((id) => visibleIds.has(id));
      const changed = nextSelectedMaskIds.length !== selectedMaskIds.length
        || nextSelectedMaskIds.some((id, index) => id !== selectedMaskIds[index]);
      if (changed) {
        setSelectedMaskIds(nextSelectedMaskIds);
      }
    }, [frameMasks, selectedMaskIds, setSelectedMaskIds]);

    const handleWheel = (e: any) => {
      e.evt.preventDefault();
      const scaleBy = 1.1;
      const stage = e.target.getStage();
      const oldScale = stage.scaleX();
      const mousePointTo = {
        x: stage.getPointerPosition().x / oldScale - stage.x() / oldScale,
        y: stage.getPointerPosition().y / oldScale - stage.y() / oldScale,
      };
      const newScale = e.evt.deltaY < 0 ? oldScale * scaleBy : oldScale / scaleBy;
      setScale(newScale);
      setPosition({
        x: -(mousePointTo.x - stage.getPointerPosition().x / newScale) * newScale,
        y: -(mousePointTo.y - stage.getPointerPosition().y / newScale) * newScale,
      });
    };

    const handleMouseMove = (e: any) => {
      const stage = e.target.getStage();
      if (!stage) return;
      const pos = stage.getPointerPosition();
      if (pos) {
         const imageX = (pos.x - position.x) / scale;
         const imageY = (pos.y - position.y) / scale;
         setCursorPos({ x: imageX, y: imageY });
      }
      if (effectiveTool === 'box_select' && boxStart) {
        const relPos = stage.getRelativePointerPosition?.();
        if (relPos) {
          setBoxCurrent({ x: relPos.x, y: relPos.y });
        }
      }
    };

    const runInference = useCallback(async () => {
      if (points.length === 0 && !promptBox) {
        setInferenceMessage('请先放置正/反向提示点或框选区域。');
        return;
      }
      if (!currentFrame?.id) {
        console.warn('AI inference skipped: no project frame is selected');
        setInferenceMessage('请先在项目工作区选择一帧图像。');
        return;
      }

      const imageWidth = currentFrame.width || image?.naturalWidth || image?.width || 0;
      const imageHeight = currentFrame.height || image?.naturalHeight || image?.height || 0;
      if (imageWidth <= 0 || imageHeight <= 0) {
        console.warn('AI inference skipped: active frame dimensions are unavailable');
        setInferenceMessage('当前帧缺少宽高信息，无法推理。');
        return;
      }

      setIsInferencing(true);
      setInferenceMessage('');
      try {
        const result = await predictMask({
          imageId: currentFrame.id,
          imageWidth,
          imageHeight,
          model: aiModel,
          points: points.length > 0 ? points.map((p) => ({ x: p.x, y: p.y, type: p.type })) : undefined,
          box: promptBox || undefined,
          options: {
            crop_to_prompt: cropMode,
            auto_filter_background: autoDeleteBg,
            min_score: autoDeleteBg ? 0.05 : 0,
          },
        });

        const masksToApply = result.masks.slice(0, 1);

        if (masksToApply.length === 0) {
          setInferenceMessage('模型没有返回可用区域，请调整提示点后重试。');
        } else {
          setInferenceMessage(result.masks.length > 1
            ? `${selectedModelStatus?.label || 'SAM 2.1'} 返回 ${result.masks.length} 个候选，已采用最高分区域。`
            : `已生成 ${masksToApply.length} 个候选区域。`);
        }
        const generatedMasks: Mask[] = masksToApply.map((m) => {
          const label = activeClass?.name || m.label;
          const color = activeClass?.color || m.color;
          return {
            id: m.id,
            frameId: currentFrame.id,
            templateId: activeTemplateId || undefined,
            classId: activeClass?.id,
            className: activeClass?.name,
            classZIndex: activeClass?.zIndex,
            saveStatus: 'draft',
            saved: false,
            pathData: m.pathData,
            label,
            color,
            segmentation: m.segmentation,
            bbox: m.bbox,
            area: m.area,
            metadata: {
              source: 'ai_segmentation',
              promptBox: promptBox || null,
              promptPointCount: points.length,
              promptNegativePointCount: points.filter((point) => point.type === 'neg').length,
            },
          };
        });

        const previousAiMaskIds = new Set(aiMaskIds);
        const generatedMaskIds = generatedMasks.map((mask) => mask.id);
        setMasks([
          ...masks.filter((mask) => !previousAiMaskIds.has(mask.id)),
          ...generatedMasks,
        ]);
        setAiMaskIds(generatedMaskIds);
        if (generatedMaskIds.length > 0) {
          setSelectedMaskIds(generatedMaskIds);
        } else {
          setSelectedMaskIds(selectedMaskIds.filter((id) => !previousAiMaskIds.has(id)));
        }
      } catch (err) {
        console.error('AI inference failed:', err);
        const detail = (err as any)?.response?.data?.detail;
        setInferenceMessage(detail || 'AI 推理失败，请查看模型状态或后端日志。');
      } finally {
        setIsInferencing(false);
      }
    }, [activeClass, activeTemplateId, aiMaskIds, aiModel, autoDeleteBg, cropMode, currentFrame?.height, currentFrame?.id, currentFrame?.width, image?.height, image?.naturalHeight, image?.naturalWidth, image?.width, masks, points, promptBox, selectedMaskIds, selectedModelStatus?.label, setMasks, setSelectedMaskIds]);

    const clearAiLayer = useCallback(() => {
      setPoints([]);
      setPromptBox(null);
      setBoxStart(null);
      setBoxCurrent(null);
      if (aiMaskIds.length === 0) return;
      const idsToRemove = new Set(aiMaskIds);
      setMasks(masks.filter((mask) => !idsToRemove.has(mask.id)));
      setSelectedMaskIds(selectedMaskIds.filter((id) => !idsToRemove.has(id)));
      setAiMaskIds([]);
    }, [aiMaskIds, masks, selectedMaskIds, setMasks, setSelectedMaskIds]);

    const deleteAiMasksById = useCallback((maskIds: string[]) => {
      const aiIds = new Set(aiMaskIds);
      const idsToRemove = new Set(maskIds.filter((id) => aiIds.has(id)));
      if (idsToRemove.size === 0) return;
      setMasks(masks.filter((mask) => !idsToRemove.has(mask.id)));
      setAiMaskIds((currentIds) => currentIds.filter((id) => !idsToRemove.has(id)));
      setSelectedMaskIds(selectedMaskIds.filter((id) => !idsToRemove.has(id)));
    }, [aiMaskIds, masks, selectedMaskIds, setMasks, setSelectedMaskIds]);

    const deleteSelectedAiMasks = useCallback(() => {
      deleteAiMasksById(selectedMaskIds);
    }, [deleteAiMasksById, selectedMaskIds]);

    const removePromptPoint = useCallback((pointIndex: number) => {
      setPoints((currentPoints) => currentPoints.filter((_, index) => index !== pointIndex));
    }, []);

    const removeLastPromptPoint = useCallback(() => {
      setPoints((currentPoints) => currentPoints.slice(0, -1));
    }, []);

    const addPromptPointFromEvent = useCallback((event: any) => {
      if (effectiveTool !== 'point_pos' && effectiveTool !== 'point_neg') return false;
      const stage = event.target?.getStage?.();
      const pos = stage?.getRelativePointerPosition?.();
      if (!pos) return false;
      setPoints((currentPoints) => [
        ...currentPoints,
        { x: pos.x, y: pos.y, type: effectiveTool === 'point_pos' ? 'pos' : 'neg' },
      ]);
      return true;
    }, [effectiveTool]);

    useEffect(() => {
      const handleKeyDown = (event: KeyboardEvent) => {
        const target = event.target as HTMLElement | null;
        const tagName = target?.tagName?.toLowerCase();
        if (tagName === 'input' || tagName === 'textarea' || target?.isContentEditable) return;
        if (event.key !== 'Delete' && event.key !== 'Backspace') return;
        const selectedAiIds = selectedMaskIds.filter((id) => aiMaskIds.includes(id));
        if (selectedAiIds.length === 0) return;
        event.preventDefault();
        deleteAiMasksById(selectedAiIds);
      };

      window.addEventListener('keydown', handleKeyDown);
      return () => window.removeEventListener('keydown', handleKeyDown);
    }, [aiMaskIds, deleteAiMasksById, selectedMaskIds]);

    const handleStageMouseDown = useCallback((event: any) => {
      if (effectiveTool !== 'box_select') return;
      const stage = event.target?.getStage?.();
      const pos = stage?.getRelativePointerPosition?.();
      if (!pos) return;
      setBoxStart({ x: pos.x, y: pos.y });
      setBoxCurrent({ x: pos.x, y: pos.y });
      setInferenceMessage('');
    }, [effectiveTool]);

    const handleStageMouseUp = useCallback(() => {
      if (effectiveTool !== 'box_select' || !boxStart || !boxCurrent) return;
      const x1 = Math.min(boxStart.x, boxCurrent.x);
      const y1 = Math.min(boxStart.y, boxCurrent.y);
      const x2 = Math.max(boxStart.x, boxCurrent.x);
      const y2 = Math.max(boxStart.y, boxCurrent.y);
      if (Math.abs(x2 - x1) > 5 && Math.abs(y2 - y1) > 5) {
        setPromptBox({ x1, y1, x2, y2 });
        setPoints([]);
        setInferenceMessage('已框选区域，可执行分割，或继续添加正/反向点细化。');
      }
      setBoxStart(null);
      setBoxCurrent(null);
    }, [boxCurrent, boxStart, effectiveTool]);

    const handleStageClick = (e: any) => {
      if (effectiveTool === 'move') return;
      if (effectiveTool === 'box_select') return;
      addPromptPointFromEvent(e);
    };

    return (
        <div className="w-full h-full flex bg-[#0a0a0a]">
            {/* Left AI Controller Panel */}
            <aside className="w-80 bg-[#0d0d0d] flex flex-col border-r border-white/5 shrink-0 z-10 overflow-hidden">
                <div className="h-16 border-b border-white/5 flex items-center px-6 shrink-0 justify-between">
                    <div className="flex items-center font-medium text-[11px] uppercase tracking-widest text-cyan-400">
                        <Sparkles size={16} className="mr-3 text-cyan-400" />
                        AI智能分割引擎
                    </div>
                </div>

                <div className="flex-1 overflow-y-auto p-6 flex flex-col gap-8">
                    {/* Model Status */}
                    <div>
                        <h3 className="text-[10px] font-bold text-gray-500 uppercase tracking-widest mb-3">视觉基础模型</h3>
                        <div className="bg-[#111] border border-white/5 p-3 rounded-lg">
                          <div className="flex items-center justify-between">
                            <span className="text-xs uppercase tracking-wider font-mono text-white">{selectedModelStatus?.label || 'SAM 2.1'}</span>
                            <span className={cn("text-xs", modelCanInfer ? "text-emerald-400" : "text-amber-400")}>
                              {modelCanInfer ? '可用' : '不可用'}
                            </span>
                          </div>
                          <div className="mt-3 grid grid-cols-2 gap-2">
                            {SAM2_MODEL_OPTIONS.map((option) => {
                              const status = modelStatus?.models.find((model) => model.id === option.id);
                              const available = status?.available ?? false;
                              const selected = aiModel === option.id;
                              return (
                                <button
                                  key={option.id}
                                  type="button"
                                  onClick={() => setAiModel(option.id)}
                                  className={cn(
                                    "h-8 rounded border px-2 text-[10px] uppercase tracking-wider transition-colors flex items-center justify-between",
                                    selected
                                      ? "bg-cyan-500/10 border-cyan-400/40 text-cyan-300"
                                      : "bg-white/[0.03] border-white/5 text-gray-400 hover:bg-white/5 hover:text-gray-200"
                                  )}
                                >
                                  <span>{option.shortLabel}</span>
                                  <span className={cn("h-1.5 w-1.5 rounded-full", available ? "bg-emerald-400" : "bg-amber-400")} />
                                </button>
                              );
                            })}
                          </div>
                        </div>
                        <div className="mt-2 text-[10px] text-gray-500 leading-relaxed">
                          <div>{selectedModelStatus?.message || '正在读取模型状态...'}</div>
                          <div>GPU: {modelStatus?.gpu.available ? `${modelStatus.gpu.name || 'CUDA'} 可用` : '不可用或未检测到 CUDA'}</div>
                        </div>
                    </div>

                    {/* Prompt Tools */}
                    <div>
                        <h3 className="text-[10px] font-bold text-gray-500 uppercase tracking-widest mb-3">交互式提示工具</h3>
                        <div className="grid grid-cols-2 gap-3">
                        <button 
                            onClick={() => setActiveTool('point_pos')}
                            className={cn("flex flex-col items-center justify-center p-4 rounded-lg border transition-all", effectiveTool === 'point_pos' ? "bg-green-500/10 border-green-500/30 text-green-400 shadow-[0_0_15px_rgba(34,197,94,0.1)]" : "bg-[#111] border-white/5 text-gray-400 hover:bg-white/5 hover:text-gray-200")}
                        >
                            <PlusCircle size={22} className="mb-3" />
                            <span className="text-[10px] uppercase tracking-wider font-semibold">正向选点</span>
                        </button>
                        
                        <button 
                            onClick={() => setActiveTool('point_neg')}
                            className={cn("flex flex-col items-center justify-center p-4 rounded-lg border transition-all", effectiveTool === 'point_neg' ? "bg-red-500/10 border-red-500/30 text-red-500 shadow-[0_0_15px_rgba(239,68,68,0.1)]" : "bg-[#111] border-white/5 text-gray-400 hover:bg-white/5 hover:text-gray-200")}
                        >
                            <MinusCircle size={22} className="mb-3" />
                            <span className="text-[10px] uppercase tracking-wider font-semibold">反向选点</span>
                        </button>
                        
                        <button 
                            onClick={() => setActiveTool('box_select')}
                            className={cn("flex flex-col items-center justify-center p-4 rounded-lg border transition-all", effectiveTool === 'box_select' ? "bg-blue-500/10 border-blue-500/30 text-blue-400 shadow-[0_0_15px_rgba(59,130,246,0.1)]" : "bg-[#111] border-white/5 text-gray-400 hover:bg-white/5 hover:text-gray-200")}
                        >
                            <SquareDashed size={22} className="mb-3" />
                            <span className="text-[10px] uppercase tracking-wider font-semibold">边界框选</span>
                        </button>

                        <button 
                            onClick={() => setActiveTool('move')}
                            className={cn("flex flex-col items-center justify-center p-4 rounded-lg border transition-all", effectiveTool === 'move' ? "bg-white/10 border-white/20 text-white shadow-[0_0_15px_rgba(255,255,255,0.05)]" : "bg-[#111] border-white/5 text-gray-400 hover:bg-white/5 hover:text-gray-200")}
                        >
                            <Target size={22} className="mb-3" />
                            <span className="text-[10px] uppercase tracking-wider font-semibold">视口控制</span>
                        </button>
                        </div>
                    </div>

                    {/* Parameters */}
                    <div>
                        <h3 className="text-[10px] font-bold text-gray-500 uppercase tracking-widest mb-3 flex items-center gap-2">核心参数设定</h3>
                        <div className="space-y-4 bg-[#111] rounded-lg p-5 border border-white/5">
                        <div className="flex items-center justify-between cursor-pointer group" onClick={() => setCropMode(!cropMode)}>
                            <span className="text-[11px] text-gray-400 uppercase tracking-wider font-medium group-hover:text-gray-200 transition-colors">局部专注模式（自动裁剪无锚区域）</span>
                            <button className={cn("w-8 h-4 rounded-full transition-colors relative", cropMode ? "bg-cyan-500" : "bg-white/20")}>
                                <div className={cn("absolute top-0.5 left-0.5 w-3 h-3 bg-white rounded-full transition-transform shadow-sm", cropMode ? "translate-x-4" : "")} />
                            </button>
                        </div>
                        
                        <div className="flex items-center justify-between cursor-pointer group" onClick={() => setAutoDeleteBg(!autoDeleteBg)}>
                            <span className="text-[11px] text-gray-400 uppercase tracking-wider font-medium group-hover:text-gray-200 transition-colors">严格除杂模式（自动清理干涉点）</span>
                            <button className={cn("w-8 h-4 rounded-full transition-colors relative", autoDeleteBg ? "bg-cyan-500" : "bg-white/20")}>
                                <div className={cn("absolute top-0.5 left-0.5 w-3 h-3 bg-white rounded-full transition-transform shadow-sm", autoDeleteBg ? "translate-x-4" : "")} />
                            </button>
                        </div>

                        <div className="space-y-2">
                            <div className="flex items-center justify-between">
                                <label htmlFor="ai-mask-opacity" className="text-[11px] text-gray-400 uppercase tracking-wider font-medium">遮罩清晰度</label>
                                <span className="text-[10px] font-mono text-cyan-400">{maskOpacity}%</span>
                            </div>
                            <input
                                id="ai-mask-opacity"
                                type="range"
                                min="20"
                                max="100"
                                step="5"
                                value={maskOpacity}
                                onChange={(event) => setMaskOpacity(Number(event.target.value))}
                                className="w-full accent-cyan-400"
                            />
                        </div>
                        </div>
                    </div>
                </div>

                <div className="p-6 bg-[#0a0a0a] border-t border-white/5 shrink-0 flex flex-col gap-3">
                    <button 
                        onClick={runInference}
                        disabled={isInferencing || !currentFrame || !modelCanInfer}
                        className={cn(
                            "w-full py-3.5 rounded-lg flex items-center justify-center gap-2 transition-all shadow-lg font-medium tracking-wide text-xs uppercase",
                            isInferencing || !currentFrame || !modelCanInfer
                                ? "bg-cyan-500/50 text-black/70 cursor-not-allowed"
                                : "bg-cyan-500 hover:bg-cyan-400 text-black shadow-cyan-500/20 hover:shadow-cyan-500/40"
                        )}
                    >
                        {isInferencing ? <Loader2 size={16} className="animate-spin" /> : <Sparkles size={16} />}
                        {isInferencing ? '推理中...' : modelCanInfer ? '执行高精度语义分割' : '当前模型不可用'}
                    </button>
                    {inferenceMessage && (
                      <div className="rounded border border-white/10 bg-white/5 px-3 py-2 text-[11px] leading-relaxed text-gray-300">
                        {inferenceMessage}
                      </div>
                    )}
                    <button 
                        onClick={() => {
                          setActiveTool('edit_polygon');
                          onSendToWorkspace();
                        }}
                        className="w-full py-3.5 rounded-lg flex items-center justify-center gap-2 transition-all font-medium tracking-wide text-xs uppercase bg-white/5 hover:bg-white/10 text-gray-300 border border-white/5 hover:border-white/10"
                    >
                        <SendToBack size={16} /> 推送至工作区编辑
                    </button>
                </div>
            </aside>

            {/* Right Canvas Area */}
            <main className="flex-1 bg-[#151515] relative overflow-hidden flex flex-col">
                <header className="h-16 border-b border-white/5 bg-[#111] flex items-center justify-between px-6 shrink-0">
                    <div className="flex flex-col">
                       <h2 className="text-sm font-semibold tracking-wide text-white">模型端推理侧可视化 (Visualizer)</h2>
                       <span className="text-[10px] text-gray-500 uppercase tracking-widest font-mono">SAM 2.1 动态推理渲染</span>
                    </div>
                    <div className="flex items-center gap-4">
                       <button
                          onClick={undoMasks}
                          disabled={maskHistory.length === 0}
                          className="w-8 h-8 rounded text-gray-400 hover:bg-white/5 hover:text-white flex items-center justify-center transition-colors disabled:opacity-30 disabled:hover:bg-transparent disabled:hover:text-gray-400 disabled:cursor-not-allowed"
                          title="撤销操作 (Ctrl+Z)"
                       >
                          <Undo size={14} />
                       </button>
                       <button
                          onClick={redoMasks}
                          disabled={maskFuture.length === 0}
                          className="w-8 h-8 rounded text-gray-400 hover:bg-white/5 hover:text-white flex items-center justify-center transition-colors disabled:opacity-30 disabled:hover:bg-transparent disabled:hover:text-gray-400 disabled:cursor-not-allowed"
                          title="重做操作 (Ctrl+Shift+Z)"
                       >
                          <Redo size={14} />
                       </button>
                       <div className="w-px h-4 bg-white/10 mx-1"></div>
                       <button
                          className="flex items-center gap-2 text-xs text-gray-400 hover:text-white transition-colors bg-white/5 hover:bg-white/10 px-3 py-1.5 rounded-md border border-white/5 disabled:opacity-30 disabled:hover:bg-white/5 disabled:hover:text-gray-400 disabled:cursor-not-allowed"
                          onClick={removeLastPromptPoint}
                          disabled={points.length === 0}
                          title="删除最近锚点"
                          aria-label="删除最近锚点"
                       >
                          <XCircle size={14} /> 删除最近锚点
                       </button>
                       <button
                          className="flex items-center gap-2 text-xs text-gray-400 hover:text-white transition-colors bg-white/5 hover:bg-white/10 px-3 py-1.5 rounded-md border border-white/5 disabled:opacity-30 disabled:hover:bg-white/5 disabled:hover:text-gray-400 disabled:cursor-not-allowed"
                          onClick={deleteSelectedAiMasks}
                          disabled={!selectedMaskIds.some((id) => aiMaskIds.includes(id))}
                          title="删除选中候选"
                          aria-label="删除选中候选"
                       >
                          <Trash2 size={14} /> 删除选中候选
                       </button>
                       <button className="text-xs text-gray-400 hover:text-white transition-colors px-3 py-1.5" onClick={clearAiLayer}>
                          清空全体锚点
                       </button>
                    </div>
                </header>
                
                <div className="flex-1 relative p-8">
                    <div className="w-full h-full relative border border-white/5 rounded shadow-2xl bg-[#1e1e1e] overflow-hidden cursor-crosshair">
                        {!currentFrame && (
                          <div className="absolute inset-0 z-20 flex items-center justify-center bg-[#151515] text-xs text-gray-500">
                            请先在项目库选择项目并生成帧
                          </div>
                        )}
                        {toolHint && (
                          <div className="absolute top-4 left-4 z-20 max-w-sm rounded-lg border border-cyan-400/20 bg-[#0d0d0d]/95 px-3 py-2 shadow-xl pointer-events-none">
                            <div className="text-[10px] font-semibold uppercase tracking-widest text-cyan-300">{toolHint.title}</div>
                            <div className="mt-1 text-xs leading-relaxed text-gray-300">{toolHint.body}</div>
                          </div>
                        )}
                        <Stage
                            width={window.innerWidth - 320 - 64}
                            height={window.innerHeight - 64 - 64}
                            onWheel={handleWheel}
                            onMouseMove={handleMouseMove}
                            onMouseDown={handleStageMouseDown}
                            onMouseUp={handleStageMouseUp}
                            onClick={handleStageClick}
                            scaleX={scale}
                            scaleY={scale}
                            x={position.x}
                            y={position.y}
                            draggable={effectiveTool === 'move'}
                        >
                            <Layer>
                                {/* Background Image */}
                                {image && (
                                    <KonvaImage 
                                        image={image} 
                                        x={0} 
                                        y={0}
                                        opacity={0.8}
                                    />
                                )}

                                {boxRect && (
                                  <Rect
                                    x={boxRect.x}
                                    y={boxRect.y}
                                    width={boxRect.width}
                                    height={boxRect.height}
                                    fill="rgba(59, 130, 246, 0.12)"
                                    stroke="#60a5fa"
                                    strokeWidth={2 / scale}
                                    dash={[5 / scale, 5 / scale]}
                                  />
                                )}
                                
                                {/* AI Returned Masks */}
                                {frameMasks.map((mask) => {
                                  const isSelected = selectedMaskIds.includes(mask.id);
                                  const previewOpacity = isSelected
                                    ? maskOpacity / 100
                                    : Math.max(0.18, (maskOpacity / 100) * 0.62);
                                  return (
                                    <Group key={mask.id} opacity={previewOpacity}>
                                        <Path
                                            data={mask.pathData}
                                            fill={mask.color}
                                            stroke={mask.color}
                                            strokeWidth={(isSelected ? 2.5 : 1) / scale}
                                            onClick={(event: any) => {
                                                if (addPromptPointFromEvent(event)) {
                                                  event.cancelBubble = true;
                                                  return;
                                                }
                                                event.cancelBubble = true;
                                                setSelectedMaskIds([mask.id]);
                                            }}
                                            onTap={(event: any) => {
                                                if (addPromptPointFromEvent(event)) {
                                                  event.cancelBubble = true;
                                                  return;
                                                }
                                                event.cancelBubble = true;
                                                setSelectedMaskIds([mask.id]);
                                            }}
                                        />
                                    </Group>
                                  );
                                })}

                                {/* Points */}
                                {points.map((p, i) => (
                                <Group key={i} x={p.x} y={p.y}>
                                    <Circle 
                                        radius={6 / scale} 
                                        fill={p.type === 'pos' ? '#22c55e' : '#ef4444'}
                                        stroke="#ffffff"
                                        strokeWidth={2 / scale}
                                        shadowColor="black"
                                        shadowBlur={4}
                                        onClick={(event: any) => {
                                          event.cancelBubble = true;
                                          removePromptPoint(i);
                                        }}
                                        onTap={(event: any) => {
                                          event.cancelBubble = true;
                                          removePromptPoint(i);
                                        }}
                                    />
                                    <Circle 
                                        radius={1.5 / scale} 
                                        fill="#ffffff"
                                        onClick={(event: any) => {
                                          event.cancelBubble = true;
                                          removePromptPoint(i);
                                        }}
                                        onTap={(event: any) => {
                                          event.cancelBubble = true;
                                          removePromptPoint(i);
                                        }}
                                    />
                                </Group>
                                ))}
                            </Layer>
                        </Stage>
                        <div className="absolute bottom-4 left-4 flex gap-4 text-[10px] font-mono text-gray-500 pointer-events-none">
                            <span>光标坐标: {cursorPos.x.toFixed(2)}, {cursorPos.y.toFixed(2)}</span>
                            <span>缩放比率: {(scale * 100).toFixed(0)}%</span>
                            <span>遮罩数: {frameMasks.length}</span>
                        </div>
                    </div>
                </div>
            </main>

            {/* Right Ontology / Label Assignment Panel */}
            <OntologyInspector />
        </div>
    );
}
