import React, { useEffect, useState, useRef } from 'react';
import { flushSync } from 'react-dom';
import { useNavigate, useSearchParams } from 'react-router-dom';
import Sidebar from '../components/Sidebar';
import { 
  Check, Printer, Undo, Redo, Bold, Italic, Underline, 
  AlignLeft, AlignCenter, AlignRight, Table, Image as ImageIcon,
  Video, Play, Pause, Plus, X, ChevronLeft, Download
} from 'lucide-react';
import { User, Report, Template, CapturedFrame, SystemSettings, FormField, DEFAULT_FORM_FIELDS } from '../types';
import { defaultReportContent } from '../utils/defaultContent';
import { printDocument } from '../utils/print';
import { storage } from '../utils/storage';

export default function ReportEditor() {
  const navigate = useNavigate();
  const [searchParams] = useSearchParams();
  const reportId = searchParams.get('id');
  const restoreFlag = searchParams.get('restore');
  
  const [currentUser, setCurrentUser] = useState<User | null>(null);
  const [reportData, setReportData] = useState<Partial<Report>>({
    title: '腹腔镜胆囊切除术报告',
    patientName: '',
    hospitalId: '',
    patientGender: '',
    patientAge: '',
    department: '',
    bedNumber: '',
    surgeryDate: '',
    startHour: '',
    startMinute: '',
    endHour: '',
    endMinute: '',
    surgeon: [],
    assistant: [],
    anesthesiologist: [],
    anesthesiaType: '',
    reportNote: '',
    status: 'draft'
  });

  const [templates, setTemplates] = useState<Template[]>([]);
  const [videos, setVideos] = useState<{id: string, name: string, url: string, duration: number}[]>([]);
  const [currentVideoIndex, setCurrentVideoIndex] = useState(-1);
  const [capturedFrames, setCapturedFrames] = useState<CapturedFrame[]>([]);
  const [isPlaying, setIsPlaying] = useState(false);
  const [currentTime, setCurrentTime] = useState(0);
  const [duration, setDuration] = useState(0);
  const [isSaved, setIsSaved] = useState(false);
  const [exportModalOpen, setExportModalOpen] = useState(false);
  const [loadedTemplateId, setLoadedTemplateId] = useState('');
  const [pendingTemplateId, setPendingTemplateId] = useState<string | null>(null);
  const prevVideoCountRef = useRef(0);
  
  const [activeTab, setActiveTab] = useState<'info' | 'video'>('info');
  const [multiSelectOptions, setMultiSelectOptions] = useState<Record<string, string[]>>({
    surgeon: ['张医生', '李医生', '王医生'],
    assistant: ['赵医生', '钱医生', '孙医生'],
    anesthesiologist: ['周医生', '吴医生', '郑医生']
  });
  const [anesthesiaOptions, setAnesthesiaOptions] = useState<string[]>(['全麻', '局麻', '腰麻', '硬膜外麻醉', '静脉麻醉', '吸入麻醉']);
  const [openDropdown, setOpenDropdown] = useState<string | null>(null);
  const [multiInputText, setMultiInputText] = useState<Record<string, string>>({});
  const [touched, setTouched] = useState<Record<string, boolean>>({});
  const [formFields, setFormFields] = useState<FormField[]>([]);
  const [imagePickerOpen, setImagePickerOpen] = useState(false);
  const [imagePickerTarget, setImagePickerTarget] = useState<HTMLElement | null>(null);
  const [imageAssets, setImageAssets] = useState<{id: string; name: string; dataUrl: string}[]>([]);
  const [placeholderModal, setPlaceholderModal] = useState({
    isOpen: false, width: '200', height: '200', mode: 'frame' as 'frame' | 'manual'
  });
  const [tableModal, setTableModal] = useState({
    isOpen: false, rows: '2', cols: '3'
  });

  const editorRef = useRef<HTMLDivElement>(null);
  const videoRef = useRef<HTMLVideoElement>(null);
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const videoInputRef = useRef<HTMLInputElement>(null);
  const contentLoadedRef = useRef(false);
  const contentRef = useRef('');
  const stateRef = useRef({ reportData, videos, capturedFrames, activeTab, loadedTemplateId });

  const draftKey = currentUser ? `reportEditorDraft_${currentUser.username}` : '';

  const updatePageHeight = () => {
    if (!editorRef.current) return;
    const contentHeight = editorRef.current.scrollHeight;
    const pageHeightMm = 297;
    const mmToPx = 3.7795275591;
    const pages = Math.max(2, Math.ceil(contentHeight / (pageHeightMm * mmToPx)));
    editorRef.current.style.minHeight = `${pages * pageHeightMm}mm`;
  };

  const saveDraftToStorage = React.useCallback(() => {
    const user = storage.get<User | null>('currentUser', null);
    const key = user ? `reportEditorDraft_${user.username}` : '';
    if (key) {
      const currentContent = contentRef.current || editorRef.current?.innerHTML || '';
      storage.set(key, {
        content: currentContent,
        draftReportId: reportId || null,
        reportData: stateRef.current.reportData,
        videos: stateRef.current.videos,
        capturedFrames: stateRef.current.capturedFrames,
        activeTab: stateRef.current.activeTab,
        loadedTemplateId: stateRef.current.loadedTemplateId
      });
    }
  }, [reportId]);

  useEffect(() => {
    const user = storage.get<User | null>('currentUser', null);
    if (!user) { navigate('/'); return; }
    setCurrentUser(user);

    const savedMulti = storage.get<Record<string, string[]> | null>('multiSelectOptions', null);
    if (savedMulti) setMultiSelectOptions(savedMulti);
    const savedAnesthesia = storage.get<string[] | null>('anesthesiaOptions', null);
    if (savedAnesthesia) setAnesthesiaOptions(savedAnesthesia);

    const savedFields = storage.get<FormField[]>('formFieldsConfig', []);
    if (savedFields.length > 0) {
      setFormFields(savedFields);
    } else {
      setFormFields(DEFAULT_FORM_FIELDS);
      storage.set('formFieldsConfig', DEFAULT_FORM_FIELDS);
    }

    const savedAssets = storage.get<{id: string; name: string; dataUrl: string}[]>('imageAssets', []);
    setImageAssets(savedAssets);

    const allTemplates = storage.get<Template[]>('templates', []);
    const visibleTplIds = Array.isArray(user.visibleTemplates) ? user.visibleTemplates : allTemplates.map(t => t.id);
    const filteredTemplates = allTemplates.filter(t => visibleTplIds.includes(t.id));
    setTemplates(filteredTemplates);

    if (reportId) {
      const draft = storage.get<Record<string, any> | null>(draftKey, null);
      if (draft && draft.draftReportId === reportId) {
        if (draft.reportData) setReportData(draft.reportData);
        if (draft.videos) {
          setVideos(draft.videos);
          if (draft.videos.length > 0) setCurrentVideoIndex(0);
          prevVideoCountRef.current = draft.videos.length;
        }
        if (draft.capturedFrames) {
          setCapturedFrames(draft.capturedFrames.sort((a: CapturedFrame, b: CapturedFrame) => a.time - b.time));
        }
        if (draft.activeTab) setActiveTab(draft.activeTab);
        stateRef.current = {
          ...stateRef.current,
          reportData: draft.reportData,
          videos: draft.videos,
          capturedFrames: draft.capturedFrames,
          loadedTemplateId: draft.loadedTemplateId || ''
        };
        if (editorRef.current && typeof draft.content === 'string' && draft.content.trim().length > 0) {
          editorRef.current.innerHTML = draft.content;
          contentRef.current = draft.content;
          contentLoadedRef.current = true;
          setLoadedTemplateId(draft.loadedTemplateId || '');
          setTimeout(() => updatePageHeight(), 0);
        }
      } else {
        const reports = storage.get<Report[]>('reports', []);
        const found = reports.find(r => r.id === reportId);
        if (found) {
          setReportData(found);
          stateRef.current = {
            ...stateRef.current,
            reportData: found,
            videos: found.videos || [],
            capturedFrames: found.capturedFrames || []
          };
          if (editorRef.current) {
            const restoreContent = storage.getSession<string | null>(`restore_${reportId}`, null);
            if (restoreFlag && restoreContent) {
              editorRef.current.innerHTML = restoreContent;
              storage.removeSession(`restore_${reportId}`);
            } else {
              editorRef.current.innerHTML = found.content;
              contentRef.current = found.content;
            }
            contentLoadedRef.current = true;
            setTimeout(() => updatePageHeight(), 0);
          }
          if (found.capturedFrames) {
            setCapturedFrames(found.capturedFrames.sort((a, b) => a.time - b.time));
          }
          if (found.videos) {
            setVideos(found.videos);
            if (found.videos.length > 0) setCurrentVideoIndex(0);
            prevVideoCountRef.current = found.videos.length;
          }
        }
      }
    } else {
      const draft = storage.get<Record<string, any> | null>(draftKey, null);
      if (draft && !draft.draftReportId) {
        if (draft.reportData) setReportData(draft.reportData);
        if (draft.videos) {
          setVideos(draft.videos);
          if (draft.videos.length > 0) setCurrentVideoIndex(0);
          prevVideoCountRef.current = draft.videos.length;
        }
        if (draft.capturedFrames) {
          setCapturedFrames(draft.capturedFrames.sort((a: CapturedFrame, b: CapturedFrame) => a.time - b.time));
        }
        if (draft.activeTab) setActiveTab(draft.activeTab);
        stateRef.current = {
          ...stateRef.current,
          reportData: draft.reportData,
          videos: draft.videos,
          capturedFrames: draft.capturedFrames,
          loadedTemplateId: draft.loadedTemplateId || ''
        };
        if (editorRef.current && typeof draft.content === 'string' && draft.content.trim().length > 0) {
          editorRef.current.innerHTML = draft.content;
          contentRef.current = draft.content;
          contentLoadedRef.current = true;
          setLoadedTemplateId(draft.loadedTemplateId || '');
          setTimeout(() => updatePageHeight(), 0);
        }
      }
      if (!contentLoadedRef.current && editorRef.current) {
        const settings = storage.get<SystemSettings>('systemSettings', {} as SystemSettings);
        if (settings.defaultTemplate && filteredTemplates.length > 0) {
          const tpl = filteredTemplates.find(t => t.id === settings.defaultTemplate);
          if (tpl) {
            setLoadedTemplateId(tpl.id);
            stateRef.current = { ...stateRef.current, loadedTemplateId: tpl.id };
            editorRef.current.innerHTML = tpl.content;
            contentRef.current = tpl.content;
          } else {
            editorRef.current.innerHTML = defaultReportContent;
            contentRef.current = defaultReportContent;
          }
        } else {
          editorRef.current.innerHTML = defaultReportContent;
          contentRef.current = defaultReportContent;
        }
        contentLoadedRef.current = true;
        setTimeout(() => updatePageHeight(), 0);
      }
    }
  }, [reportId, navigate, draftKey, restoreFlag]);

  useEffect(() => {
    const handleBeforeUnload = () => saveDraftToStorage();
    const handleVisibilityChange = () => {
      if (document.visibilityState === 'hidden') saveDraftToStorage();
    };
    window.addEventListener('beforeunload', handleBeforeUnload);
    document.addEventListener('visibilitychange', handleVisibilityChange);
    return () => {
      window.removeEventListener('beforeunload', handleBeforeUnload);
      document.removeEventListener('visibilitychange', handleVisibilityChange);
      saveDraftToStorage();
    };
  }, [saveDraftToStorage]);

  // Auto-fill current time for fields with timeDefault === 'current'
  useEffect(() => {
    if (formFields.length === 0) return;
    let hasChange = false;
    const updates: any = {};
    formFields.forEach(field => {
      if (field.timeDefault === 'current') {
        if (field.type === 'date') {
          const current = new Date().toISOString().split('T')[0];
          if (!(reportData as any)[field.key]) {
            updates[field.key] = current;
            hasChange = true;
          }
        } else if (field.type === 'time') {
          const now = new Date();
          const hh = String(now.getHours()).padStart(2, '0');
          const mm = String(now.getMinutes()).padStart(2, '0');
          if (field.key === 'startTime') {
            if (!reportData.startHour) {
              updates.startHour = hh;
              updates.startMinute = mm;
              hasChange = true;
            }
          } else if (field.key === 'endTime') {
            if (!reportData.endHour) {
              updates.endHour = hh;
              updates.endMinute = mm;
              hasChange = true;
            }
          } else {
            if (!(reportData as any)[field.key]) {
              updates[field.key] = `${hh}:${mm}`;
              hasChange = true;
            }
          }
        }
      } else if (field.timeDefault === 'specific' && field.fixedTimeValue) {
        if (field.type === 'date') {
          if (!(reportData as any)[field.key]) {
            updates[field.key] = field.fixedTimeValue;
            hasChange = true;
          }
        } else if (field.type === 'time') {
          if (field.key === 'startTime') {
            if (!reportData.startHour) {
              const [hh, mm] = field.fixedTimeValue.split(':');
              updates.startHour = hh || '';
              updates.startMinute = mm || '';
              hasChange = true;
            }
          } else if (field.key === 'endTime') {
            if (!reportData.endHour) {
              const [hh, mm] = field.fixedTimeValue.split(':');
              updates.endHour = hh || '';
              updates.endMinute = mm || '';
              hasChange = true;
            }
          } else {
            if (!(reportData as any)[field.key]) {
              updates[field.key] = field.fixedTimeValue;
              hasChange = true;
            }
          }
        }
      }
    });
    if (hasChange) {
      setReportData(prev => {
        const next = { ...prev, ...updates };
        stateRef.current = { ...stateRef.current, reportData: next };
        return next;
      });
    }
  }, [formFields]);

  useEffect(() => {
    if (!editorRef.current) return;
    const observer = new MutationObserver(() => {
      updatePageHeight();
    });
    observer.observe(editorRef.current, { childList: true, subtree: true, attributes: true, characterData: true });
    return () => observer.disconnect();
  }, [currentUser]);

  const triggerPlaceholderUpload = (placeholder: HTMLElement) => {
    const input = document.createElement('input');
    input.type = 'file';
    input.accept = 'image/*';
    input.onchange = (ev) => {
      const file = (ev.target as HTMLInputElement).files?.[0];
      if (file) {
        const reader = new FileReader();
        reader.onload = (event) => {
          const src = event.target?.result as string;
          placeholder.innerHTML = `
            <span class="delete-btn" contenteditable="false">×</span>
            <img src="${src}" style="max-width: 100%; height: auto; display: block; margin: 0 auto;" draggable="false">
          `;
          placeholder.classList.add('has-image');
          if (editorRef.current) contentRef.current = editorRef.current.innerHTML;
          saveDraftToStorage();
        };
        reader.readAsDataURL(file);
      }
    };
    input.click();
  };

  // Handle image placeholder interactions via click capture for reliable contenteditable behavior
  useEffect(() => {
    const handleEditorClick = (e: MouseEvent) => {
      // e.target may be a text node; safely resolve to an Element
      let node: Node | null = e.target as Node;
      if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
      const targetEl = node as HTMLElement | null;
      if (!targetEl) return;

      // Handle click on field-value: switch to info tab and focus corresponding input
      const fieldValue = targetEl.closest('.field-value') as HTMLElement | null;
      if (fieldValue) {
        const bindKey = fieldValue.getAttribute('data-bind');
        if (bindKey) {
          setActiveTab('info');
          stateRef.current = { ...stateRef.current, activeTab: 'info' };
          setTimeout(() => {
            const inputEl = document.getElementById(`input-${bindKey}`);
            if (inputEl) {
              inputEl.scrollIntoView({ behavior: 'smooth', block: 'center' });
              const focusable = inputEl.querySelector('input, select') as HTMLElement | null;
              if (focusable) {
                focusable.focus();
              }
            }
          }, 100);
        }
        return;
      }

      const placeholder = targetEl.closest('.image-placeholder') as HTMLElement | null;
      if (!placeholder) return;

      if (targetEl.closest('.delete-btn')) {
        e.stopPropagation();
        e.preventDefault();
        if (placeholder.classList.contains('has-image')) {
          placeholder.classList.remove('has-image');
          placeholder.innerHTML = `
            <span class="delete-btn" contenteditable="false">×</span>
            <span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">插入/点击放置图片</span>
          `;
          placeholder.style.border = '1px dashed #cbd5e1';
          placeholder.style.background = '#f8fafc';
          if (editorRef.current) contentRef.current = editorRef.current.innerHTML;
          saveDraftToStorage();
        } else {
          const range = document.createRange();
          range.selectNode(placeholder);
          const sel = window.getSelection();
          sel?.removeAllRanges();
          sel?.addRange(range);
          document.execCommand('delete');
          if (editorRef.current) contentRef.current = editorRef.current.innerHTML;
          saveDraftToStorage();
        }
        return;
      }

      if (!placeholder.classList.contains('has-image')) {
        e.preventDefault();
        e.stopPropagation();
        setImagePickerTarget(placeholder);
        setImagePickerOpen(true);
      }
    };

    const editor = editorRef.current;
    if (editor) {
      editor.addEventListener('click', handleEditorClick, true);
    }
    return () => {
      if (editor) {
        editor.removeEventListener('click', handleEditorClick, true);
      }
    };
  }, [saveDraftToStorage, currentUser]);

  // Prevent backspace from deleting image-placeholder elements
  useEffect(() => {
    const editor = editorRef.current;
    if (!editor) return;

    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.key !== 'Backspace' && e.key !== 'Delete') return;
      const sel = window.getSelection();
      if (!sel || sel.rangeCount === 0) return;
      const range = sel.getRangeAt(0);
      
      // If selection is inside a placeholder, or if the range intersects a placeholder
      let node: Node | null = range.commonAncestorContainer;
      if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
      const placeholder = (node as HTMLElement)?.closest('.image-placeholder');
      if (placeholder) {
        e.preventDefault();
        return;
      }
      
      // If collapsed and next/previous sibling is a placeholder
      if (range.collapsed) {
        const container = range.startContainer;
        const offset = range.startOffset;
        if (container.nodeType === Node.ELEMENT_NODE) {
          const next = (container as Element).children[offset];
          const prev = (container as Element).children[offset - 1];
          if ((e.key === 'Delete' && next?.classList?.contains('image-placeholder')) ||
              (e.key === 'Backspace' && prev?.classList?.contains('image-placeholder'))) {
            e.preventDefault();
          }
        }
      }
    };

    editor.addEventListener('keydown', handleKeyDown);
    return () => editor.removeEventListener('keydown', handleKeyDown);
  }, []);

  const fillPlaceholderSrc = (placeholder: HTMLElement, src: string) => {
    placeholder.innerHTML = `
      <span class="delete-btn" contenteditable="false">×</span>
      <img src="${src}" style="max-width:100%;max-height:100%;object-fit:contain;display:block;margin:0 auto;" draggable="false">
    `;
    placeholder.classList.add('has-image');
    placeholder.style.border = 'none';
    placeholder.style.background = 'transparent';
    if (editorRef.current) contentRef.current = editorRef.current.innerHTML;
    saveDraftToStorage();
  };

  const execCmd = (command: string, value: string | undefined = undefined) => {
    editorRef.current?.focus();
    document.execCommand(command, false, value);
    editorRef.current?.focus();
    if (editorRef.current) contentRef.current = editorRef.current.innerHTML;
    saveDraftToStorage();
  };

  const changeLineHeight = (height: string) => {
    const sel = window.getSelection();
    if (!sel || !sel.rangeCount) return;
    let node = sel.getRangeAt(0).commonAncestorContainer;
    if (node.nodeType === Node.TEXT_NODE) node = node.parentNode as Node;
    const block = (node as HTMLElement).closest('p, div, td, h1, h2, h3, li');
    if (block) {
      (block as HTMLElement).style.lineHeight = height;
      if (editorRef.current) contentRef.current = editorRef.current.innerHTML;
      saveDraftToStorage();
    }
  };

  const insertTable = () => {
    editorRef.current?.focus();
    setTableModal({ isOpen: true, rows: '2', cols: '3' });
  };

  const insertImage = () => {
    editorRef.current?.focus();
    setPlaceholderModal({ isOpen: true, width: '200', height: '200', mode: 'frame' });
  };

  const handleVideoUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = Array.from(e.target.files || []) as File[];
    const newVideos = files.map(file => ({
      id: Math.random().toString(36).substr(2, 9),
      name: file.name,
      url: URL.createObjectURL(file),
      duration: 0
    }));
    const combined = [...videos, ...newVideos];
    setVideos(combined);
    stateRef.current = { ...stateRef.current, videos: combined };
    setCurrentVideoIndex(videos.length); // select first newly uploaded video
    if (videoInputRef.current) videoInputRef.current.value = '';
    saveDraftToStorage();
  };

  const removeVideo = (id: string) => {
    const idx = videos.findIndex(v => v.id === id);
    const updated = videos.filter(v => v.id !== id);
    setVideos(updated);
    stateRef.current = { ...stateRef.current, videos: updated };
    if (currentVideoIndex >= updated.length) {
      setCurrentVideoIndex(updated.length > 0 ? 0 : -1);
    } else if (currentVideoIndex === idx && updated.length > 0) {
      setCurrentVideoIndex(0);
    }
    const nextFrames = capturedFrames.filter(f => f.videoIndex !== idx).map(f => {
      if (f.videoIndex > idx) return { ...f, videoIndex: f.videoIndex - 1 };
      return f;
    }).sort((a, b) => a.time - b.time);
    setCapturedFrames(nextFrames);
    stateRef.current = { ...stateRef.current, capturedFrames: nextFrames };
    saveDraftToStorage();
  };

  const selectVideo = (index: number) => {
    setCurrentVideoIndex(index);
    setIsPlaying(false);
  };

  const togglePlay = () => {
    if (!videoRef.current) return;
    if (isPlaying) videoRef.current.pause();
    else videoRef.current.play();
    setIsPlaying(!isPlaying);
  };

  const captureFrame = () => {
    if (!videoRef.current || !canvasRef.current || currentVideoIndex === -1) return;
    const video = videoRef.current;
    const canvas = canvasRef.current;
    const MAX_WIDTH = 800;
    const scale = Math.min(1, MAX_WIDTH / video.videoWidth);
    canvas.width = video.videoWidth * scale;
    canvas.height = video.videoHeight * scale;
    const ctx = canvas.getContext('2d');
    ctx?.drawImage(video, 0, 0, canvas.width, canvas.height);

    const newFrame: CapturedFrame = {
      id: Date.now(),
      videoIndex: currentVideoIndex,
      videoName: videos[currentVideoIndex].name,
      time: video.currentTime,
      timeFormatted: formatTime(video.currentTime),
      dataUrl: canvas.toDataURL('image/jpeg', 0.6),
      isManual: true
    };
    const nextFrames = [...capturedFrames, newFrame].sort((a, b) => a.time - b.time);
    setCapturedFrames(nextFrames);
    stateRef.current = { ...stateRef.current, capturedFrames: nextFrames };
    saveDraftToStorage();
  };

  const autoCaptureFrames = async () => {
    if (!videoRef.current || currentVideoIndex === -1) return;
    const video = videoRef.current;
    const settings = storage.get<SystemSettings>('systemSettings', {} as SystemSettings);
    const positions = settings.framePositions || [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60];
    const dur = video.duration || 1;

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

    const wasPlaying = !video.paused;
    if (wasPlaying) video.pause();

    let accumulatedFrames = [...capturedFrames];
    for (let i = 0; i < positions.length; i++) {
      const pos = positions[i];
      const time = (pos / 100) * dur;
      video.currentTime = time;
      await new Promise<void>(resolve => {
        const onSeeked = () => {
          video.removeEventListener('seeked', onSeeked);
          resolve();
        };
        video.addEventListener('seeked', onSeeked);
      });
      const MAX_WIDTH = 800;
      const scale = Math.min(1, MAX_WIDTH / video.videoWidth);
      canvas.width = video.videoWidth * scale;
      canvas.height = video.videoHeight * scale;
      ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
      const newFrame: CapturedFrame = {
        id: Date.now() + Math.random(),
        videoIndex: currentVideoIndex,
        videoName: videos[currentVideoIndex].name,
        time,
        timeFormatted: formatTime(time),
        dataUrl: canvas.toDataURL('image/jpeg', 0.6),
        isManual: false
      };
      accumulatedFrames = [...accumulatedFrames, newFrame].sort((a, b) => a.time - b.time);
      flushSync(() => {
        setCapturedFrames(accumulatedFrames);
      });
      stateRef.current = { ...stateRef.current, capturedFrames: accumulatedFrames };
      if (settings.autoInsertFrames && settings.autoInsertFrameIndices?.includes(i)) {
        const baseDelay = (settings.autoInsertDelay || 0) * 1000;
        const insertOrderIndex = settings.autoInsertFrameIndices.indexOf(i);
        const actualDelay = baseDelay > 0 ? baseDelay * (insertOrderIndex + 1) : 0;

        setTimeout(() => {
          if (!editorRef.current) return;
          const emptyPlaceholder = editorRef.current.querySelector('.image-placeholder:not(.has-image):not([data-mode="manual"])') as HTMLElement | null;
          if (emptyPlaceholder) {
            emptyPlaceholder.innerHTML = `
              <span class="delete-btn" contenteditable="false">×</span>
              <img src="${newFrame.dataUrl}" style="max-width: 100%; height: auto; display: block; margin: 0 auto;" draggable="false">
            `;
            emptyPlaceholder.classList.add('has-image');
            emptyPlaceholder.style.border = 'none';
            emptyPlaceholder.style.background = 'transparent';
            contentRef.current = editorRef.current.innerHTML;
            saveDraftToStorage();
          }
        }, actualDelay);
      }
    }
    if (settings.autoInsertFrames && editorRef.current) {
      contentRef.current = editorRef.current.innerHTML;
    }
    if (wasPlaying) video.play();
    saveDraftToStorage();
  };

  const formatTime = (seconds: number) => {
    const mins = Math.floor(seconds / 60);
    const secs = Math.floor(seconds % 60);
    return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
  };

  const handleDragStart = (e: React.DragEvent, frame: CapturedFrame) => {
    e.dataTransfer.setData('frameId', frame.id.toString());
  };

  const fillPlaceholder = (placeholder: HTMLElement, frame: CapturedFrame) => {
    placeholder.innerHTML = `
      <span class="delete-btn" contenteditable="false">×</span>
      <img src="${frame.dataUrl}" style="max-width:100%;max-height:100%;object-fit:contain;display:block;margin:0 auto;" draggable="false">
    `;
    placeholder.classList.add('has-image');
    placeholder.style.border = 'none';
    placeholder.style.background = 'transparent';
    if (editorRef.current) contentRef.current = editorRef.current.innerHTML;
    saveDraftToStorage();
  };

  const handleDrop = (e: React.DragEvent, placeholder: HTMLElement) => {
    e.preventDefault();
    if (placeholder.getAttribute('data-mode') === 'manual') {
      alert('此处为静态图片占位符，仅支持点击插入（如Logo/签名），不支持拖入关键帧');
      return;
    }
    const frameId = e.dataTransfer.getData('frameId');
    const frame = capturedFrames.find(f => f.id.toString() === frameId);
    if (frame) {
      fillPlaceholder(placeholder, frame);
    }
  };

  const insertFrameToPlaceholder = (frame: CapturedFrame) => {
    if (!editorRef.current) {
      alert('编辑器未准备好');
      return;
    }
    const emptyPlaceholder = editorRef.current.querySelector('.image-placeholder:not(.has-image):not([data-mode="manual"])') as HTMLElement | null;
    if (!emptyPlaceholder) {
      alert('没有可插入图片的空位');
      return;
    }
    fillPlaceholder(emptyPlaceholder, frame);
  };

  const seekToFrame = (frame: CapturedFrame) => {
    if (!videoRef.current) return;
    if (frame.videoIndex !== currentVideoIndex) {
      setCurrentVideoIndex(frame.videoIndex);
    }
    setTimeout(() => {
      if (videoRef.current) {
        videoRef.current.currentTime = frame.time;
      }
    }, 50);
  };

  const handleFrameKeyNav = (direction: 'left' | 'right') => {
    if (!videoRef.current) return;
    const delta = direction === 'left' ? -5 : 5;
    videoRef.current.currentTime = Math.max(0, Math.min(duration, videoRef.current.currentTime + delta));
  };

  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
        // Only if video tab is active or video element is focused
        if (activeTab === 'video' || document.activeElement === videoRef.current) {
          handleFrameKeyNav(e.key === 'ArrowLeft' ? 'left' : 'right');
        }
      }
    };
    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [activeTab, duration]);

  // Auto-capture frames when new videos are uploaded
  useEffect(() => {
    if (videos.length > prevVideoCountRef.current && currentVideoIndex !== -1) {
      const timer = setTimeout(() => {
        if (videoRef.current && videoRef.current.duration) {
          autoCaptureFrames();
        } else if (videoRef.current) {
          const onMeta = () => {
            autoCaptureFrames();
            videoRef.current?.removeEventListener('loadedmetadata', onMeta);
          };
          videoRef.current.addEventListener('loadedmetadata', onMeta);
        }
      }, 300);
      return () => clearTimeout(timer);
    }
    prevVideoCountRef.current = videos.length;
  }, [videos.length, currentVideoIndex]);

  // Apply selected template content
  useEffect(() => {
    if (pendingTemplateId && editorRef.current) {
      const tpl = templates.find(t => t.id === pendingTemplateId);
      if (tpl) {
        editorRef.current.innerHTML = tpl.content;
        contentRef.current = tpl.content;
        const nextReportData: any = {
          title: tpl.name || '腹腔镜胆囊切除术报告',
          patientName: '',
          hospitalId: '',
          patientGender: '',
          patientAge: '',
          department: '',
          bedNumber: '',
          surgeryDate: '',
          startHour: '',
          startMinute: '',
          endHour: '',
          endMinute: '',
          surgeon: [],
          assistant: [],
          anesthesiologist: [],
          anesthesiaType: '',
          status: 'draft'
        };
        formFields.forEach(field => {
          if (field.category === '时间') {
            if (field.timeDefault === 'specific' && field.fixedTimeValue) {
              if (field.type === 'date') {
                nextReportData[field.key] = field.fixedTimeValue;
              } else if (field.type === 'time') {
                const [hh, mm] = field.fixedTimeValue.split(':');
                if (field.key === 'startTime') {
                  nextReportData.startHour = hh || '';
                  nextReportData.startMinute = mm || '';
                } else if (field.key === 'endTime') {
                  nextReportData.endHour = hh || '';
                  nextReportData.endMinute = mm || '';
                } else {
                  nextReportData[field.key] = field.fixedTimeValue;
                }
              }
            } else if (field.timeDefault === 'current') {
              if (field.type === 'date') {
                nextReportData[field.key] = new Date().toISOString().split('T')[0];
              } else if (field.type === 'time') {
                const now = new Date();
                const hh = String(now.getHours()).padStart(2, '0');
                const mm = String(now.getMinutes()).padStart(2, '0');
                if (field.key === 'startTime') {
                  nextReportData.startHour = hh;
                  nextReportData.startMinute = mm;
                } else if (field.key === 'endTime') {
                  nextReportData.endHour = hh;
                  nextReportData.endMinute = mm;
                } else {
                  nextReportData[field.key] = `${hh}:${mm}`;
                }
              }
            }
          }
        });
        if (!nextReportData.surgeryDate) {
          nextReportData.surgeryDate = new Date().toISOString().split('T')[0];
        }
        setLoadedTemplateId(tpl.id);
        setReportData(nextReportData);
        setVideos([]);
        setCapturedFrames([]);
        setCurrentVideoIndex(-1);
        prevVideoCountRef.current = 0;
        stateRef.current = {
          ...stateRef.current,
          loadedTemplateId: tpl.id,
          reportData: nextReportData,
          videos: [],
          capturedFrames: [],
          activeTab: stateRef.current.activeTab
        };
        updatePageHeight();
        saveDraftToStorage();
      }
      setPendingTemplateId(null);
    }
  }, [pendingTemplateId, templates]);

  // Safety net: ensure editor gets initialized if ref was not ready during init effect
  React.useLayoutEffect(() => {
    if (contentLoadedRef.current || !editorRef.current) return;

    const user = storage.get<User | null>('currentUser', null);
    const key = user ? `reportEditorDraft_${user.username}` : '';
    const draft = key ? storage.get<Record<string, any> | null>(key, null) : null;

    if (reportId) {
      if (draft && draft.draftReportId === reportId && typeof draft.content === 'string' && draft.content.trim().length > 0) {
        editorRef.current.innerHTML = draft.content;
        contentRef.current = draft.content;
        contentLoadedRef.current = true;
        setLoadedTemplateId(draft.loadedTemplateId || '');
        stateRef.current = {
          ...stateRef.current,
          reportData: draft.reportData,
          videos: draft.videos,
          capturedFrames: draft.capturedFrames,
          loadedTemplateId: draft.loadedTemplateId || ''
        };
        setTimeout(() => updatePageHeight(), 0);
        return;
      }
      const reports = storage.get<Report[]>('reports', []);
      const found = reports.find(r => r.id === reportId);
      if (found) {
        const restoreContent = storage.getSession<string | null>(`restore_${reportId}`, null);
        if (restoreFlag && restoreContent) {
          editorRef.current.innerHTML = restoreContent;
          storage.removeSession(`restore_${reportId}`);
        } else {
          editorRef.current.innerHTML = found.content;
        }
        contentLoadedRef.current = true;
        stateRef.current = {
          ...stateRef.current,
          reportData: found,
          videos: found.videos || [],
          capturedFrames: found.capturedFrames || []
        };
        setTimeout(() => updatePageHeight(), 0);
        return;
      }
    } else {
      if (draft && !draft.draftReportId && typeof draft.content === 'string' && draft.content.trim().length > 0) {
        editorRef.current.innerHTML = draft.content;
        contentRef.current = draft.content;
        contentLoadedRef.current = true;
        setLoadedTemplateId(draft.loadedTemplateId || '');
        stateRef.current = {
          ...stateRef.current,
          reportData: draft.reportData,
          videos: draft.videos,
          capturedFrames: draft.capturedFrames,
          loadedTemplateId: draft.loadedTemplateId || ''
        };
        setTimeout(() => updatePageHeight(), 0);
        return;
      }
    }

    const settings = storage.get<SystemSettings>('systemSettings', {} as SystemSettings);
    const allTemplates = storage.get<Template[]>('templates', []);
    const userData = storage.get<User | null>('currentUser', null);
    const visibleTplIds = Array.isArray(userData?.visibleTemplates) ? userData.visibleTemplates : allTemplates.map(t => t.id);
    const filteredTemplates = allTemplates.filter(t => visibleTplIds.includes(t.id));
    if (settings.defaultTemplate && filteredTemplates.length > 0) {
      const tpl = filteredTemplates.find(t => t.id === settings.defaultTemplate);
      if (tpl) {
        setLoadedTemplateId(tpl.id);
        stateRef.current = { ...stateRef.current, loadedTemplateId: tpl.id };
        editorRef.current.innerHTML = tpl.content;
      } else {
        editorRef.current.innerHTML = defaultReportContent;
      }
    } else {
      editorRef.current.innerHTML = defaultReportContent;
    }
    contentLoadedRef.current = true;
    setTimeout(() => updatePageHeight(), 0);
  }, []);

  const hourOptions = Array.from({ length: 24 }, (_, i) => i.toString().padStart(2, '0'));
  const hour12Options = Array.from({ length: 12 }, (_, i) => ((i + 1).toString().padStart(2, '0')));
  const minuteOptions = Array.from({ length: 60 }, (_, i) => i.toString().padStart(2, '0'));

  const formatDateDisplay = (isoDate: string, fmt?: string): string => {
    if (!isoDate || !fmt) return isoDate || '';
    const [y, m, d] = isoDate.split('-');
    return fmt
      .replace(/YYYY/g, y || '')
      .replace(/MM/g, m || '')
      .replace(/DD/g, d || '');
  };

  const formatTimeDisplay = (timeStr: string, fmt?: string): string => {
    if (!timeStr || !fmt) return timeStr || '';
    if (fmt === '24h') fmt = 'HH:mm';
    const [h24str, mstr] = timeStr.split(':');
    const h24 = parseInt(h24str) || 0;
    const isPM = h24 >= 12;
    let h12 = h24 % 12;
    if (h12 === 0) h12 = 12;
    return fmt
      .replace(/HH/g, String(h24).padStart(2, '0'))
      .replace(/mm/g, mstr || '00')
      .replace(/hh/g, String(h12).padStart(2, '0'))
      .replace(/A/g, isPM ? '下午' : '上午');
  };

  const parseDateFromFormat = (text: string, fmt?: string): string => {
    if (!text || !fmt) return text;
    const nums = text.match(/\d+/g);
    if (!nums) return text;
    let y = '', m = '', d = '';
    if (nums.length >= 3) { y = nums[0].padStart(4, '0'); m = nums[1].padStart(2, '0'); d = nums[2].padStart(2, '0'); }
    else if (nums.length === 2) { m = nums[0].padStart(2, '0'); d = nums[1].padStart(2, '0'); y = new Date().getFullYear().toString(); }
    return `${y}-${m}-${d}`;
  };

  const parseTimeFromFormat = (text: string, fmt?: string): string => {
    if (!text || !fmt) return text;
    const nums = text.match(/\d+/g);
    const ampm = text.match(/上午|下午/);
    if (!nums || nums.length < 2) return text;
    let h = parseInt(nums[0]);
    if (ampm) {
      const isPM = ampm[0] === '下午';
      if (isPM && h !== 12) h += 12;
      if (!isPM && h === 12) h = 0;
    }
    return `${String(h).padStart(2, '0')}:${nums[1].padStart(2, '0')}`;
  };

  const to24h = (h12: number, isPM: boolean): number => {
    if (isPM && h12 !== 12) return h12 + 12;
    if (!isPM && h12 === 12) return 0;
    return h12;
  };

  const from24h = (h24: number): { h: number; isPM: boolean } => {
    const isPM = h24 >= 12;
    let h = h24 % 12;
    if (h === 0) h = 12;
    return { h, isPM };
  };

  const addTag = (field: string, value: string) => {
    const current = (reportData as any)[field] || [];
    if (!current.includes(value)) {
      const next = { ...reportData, [field]: [...current, value] };
      setReportData(next);
      stateRef.current = { ...stateRef.current, reportData: next };
      saveDraftToStorage();
    }
    // Persist custom value to global options for future reuse
    const opts = multiSelectOptions[field] || [];
    if (!opts.includes(value)) {
      const next = { ...multiSelectOptions, [field]: [...opts, value] };
      setMultiSelectOptions(next);
      storage.set('multiSelectOptions', next);
    }
    // Sync to formFieldsConfig
    const fieldDef = formFields.find(f => f.key === field);
    if (fieldDef && fieldDef.options && !fieldDef.options.includes(value)) {
      const updatedFields = formFields.map(f => f.key === field ? { ...f, options: [...(f.options || []), value] } : f);
      setFormFields(updatedFields);
      storage.set('formFieldsConfig', updatedFields);
    }
  };

  const removeTag = (field: string, value: string) => {
    const current = (reportData as any)[field] || [];
    const next = { ...reportData, [field]: current.filter((v: string) => v !== value) };
    setReportData(next);
    stateRef.current = { ...stateRef.current, reportData: next };
    saveDraftToStorage();
  };

  const removeMultiOption = (field: string, value: string) => {
    const current = multiSelectOptions[field] || [];
    const next = { ...multiSelectOptions, [field]: current.filter(v => v !== value) };
    setMultiSelectOptions(next);
    storage.set('multiSelectOptions', next);
    // Sync to formFieldsConfig
    const fieldDef = formFields.find(f => f.key === field);
    if (fieldDef && fieldDef.options) {
      const updatedFields = formFields.map(f => f.key === field ? { ...f, options: (f.options || []).filter(v => v !== value) } : f);
      setFormFields(updatedFields);
      storage.set('formFieldsConfig', updatedFields);
    }
  };

  const removeAnesthesiaOption = (value: string) => {
    const next = anesthesiaOptions.filter(v => v !== value);
    setAnesthesiaOptions(next);
    storage.set('anesthesiaOptions', next);
  };

  // Close dropdowns on outside click
  useEffect(() => {
    const handleDocClick = (e: MouseEvent) => {
      const target = e.target as HTMLElement;
      if (!target.closest('.select-dropdown-root')) {
        setOpenDropdown(null);
      }
    };
    document.addEventListener('click', handleDocClick);
    return () => document.removeEventListener('click', handleDocClick);
  }, []);

  const saveReport = (status: 'draft' | 'completed') => {
    if (status === 'completed' && (!reportData.patientName || !reportData.hospitalId)) {
      alert('请填写患者姓名和住院号');
      return;
    }

    if (status === 'completed') {
      const hasSignatureField = editorRef.current?.querySelector('[data-bind="surgeonSignature"]');
      if (hasSignatureField) {
        const hasSignatureImage = !!currentUser?.signature;
        if (!hasSignatureImage) {
          const proceed = window.confirm('提示：模板中包含【手术者签名】字段，但您的账号尚未上传电子签名图片。报告中将不显示签名图片，是否继续完成？');
          if (!proceed) return;
        }
      }
    }

    const content = editorRef.current?.innerHTML || '';
    const now = new Date().toISOString();
    const finalReport: Report = {
      ...(reportData as Report),
      id: reportId || 'RPT_' + Date.now(),
      content,
      author: currentUser?.username || '',
      authorName: currentUser?.name || '',
      createdAt: reportData.createdAt || now.split('T')[0],
      status,
      capturedFrames,
      videos,
      updatedAt: now
    };

    const reports = storage.get<Report[]>('reports', []);
    let updatedReports: Report[];
    if (reportId) {
      const old = reports.find(r => r.id === reportId);
      const history = old?.history ? [...old.history] : [];
      if (old) {
        history.push({ 
          content: old.content, 
          updatedAt: old.updatedAt || old.createdAt, 
          updatedBy: currentUser?.name || currentUser?.username || '',
          action: status === 'completed' ? 'complete_report' : 'save_draft'
        });
      }
      updatedReports = reports.map(r => r.id === reportId ? { ...finalReport, history } : r);
    } else {
      updatedReports = [...reports, finalReport];
      if (draftKey) storage.remove(draftKey);
    }

    storage.set('reports', updatedReports);
    if (draftKey) storage.remove(draftKey);
    setIsSaved(true);
    setTimeout(() => setIsSaved(false), 3000);
    if (status === 'completed') navigate('/report-manage');
  };

  const handleEditorInput = (e: React.FormEvent<HTMLDivElement>) => {
    if (editorRef.current) {
      contentRef.current = editorRef.current.innerHTML;
    }
    updatePageHeight();
    saveDraftToStorage();

    const target = e.target as HTMLElement;
    if (target && target.hasAttribute('data-bind')) {
      const fieldKey = target.getAttribute('data-bind')!;
      const newValue = target.innerText;

      const fieldDef = formFields.find(f => f.key === fieldKey);
      if (fieldKey === 'startTime') {
        let raw = newValue;
        if (fieldDef?.timeFormat && (fieldDef.timeFormat.includes('hh') || fieldDef.timeFormat.includes('A'))) {
          raw = parseTimeFromFormat(newValue, fieldDef.timeFormat);
        }
        const parts = raw.split(':');
        setReportData((prev) => {
          const next = { ...prev, startHour: parts[0] || '', startMinute: parts[1] || '' };
          stateRef.current = { ...stateRef.current, reportData: next };
          return next;
        });
      } else if (fieldKey === 'endTime') {
        let raw = newValue;
        if (fieldDef?.timeFormat && (fieldDef.timeFormat.includes('hh') || fieldDef.timeFormat.includes('A'))) {
          raw = parseTimeFromFormat(newValue, fieldDef.timeFormat);
        }
        const parts = raw.split(':');
        setReportData((prev) => {
          const next = { ...prev, endHour: parts[0] || '', endMinute: parts[1] || '' };
          stateRef.current = { ...stateRef.current, reportData: next };
          return next;
        });
      } else {
        let raw = newValue;
        if (fieldDef?.type === 'date') {
          raw = parseDateFromFormat(newValue, fieldDef.timeFormat);
        } else if (fieldDef?.type === 'time') {
          raw = parseTimeFromFormat(newValue, fieldDef.timeFormat);
        }
        setReportData((prev) => {
          const next = { ...prev, [fieldKey]: raw };
          stateRef.current = { ...stateRef.current, reportData: next };
          return next;
        });
      }
    }
  };

  // Sync form state -> rich text field values
  useEffect(() => {
    if (!editorRef.current) return;
    const bindNodes = editorRef.current.querySelectorAll('[data-bind]');
    bindNodes.forEach((node) => {
      const el = node as HTMLElement;
      const fieldKey = el.getAttribute('data-bind')!;

      if (fieldKey === 'surgeonSignature') {
        const signatureData = currentUser?.signature;
        if (signatureData) {
          const imgHtml = `<img src="${signatureData}" class="report-signature-img" alt="签名" draggable="false" />`;
          if (el.innerHTML !== imgHtml) {
            el.innerHTML = imgHtml;
            el.style.border = 'none';
            el.style.backgroundColor = 'transparent';
          }
        } else {
          const placeholder = '【请上传电子签】';
          if (el.innerText !== placeholder) {
            el.innerText = placeholder;
            el.style.border = '';
            el.style.backgroundColor = '';
          }
        }
        return;
      }

      let newValue = '';
      const fieldDef = formFields.find(f => f.key === fieldKey);
      if (fieldKey === 'startTime') {
        newValue = `${reportData.startHour || ''}:${reportData.startMinute || ''}`;
        if (newValue === ':') newValue = '';
        newValue = formatTimeDisplay(newValue, fieldDef?.timeFormat);
      } else if (fieldKey === 'endTime') {
        newValue = `${reportData.endHour || ''}:${reportData.endMinute || ''}`;
        if (newValue === ':') newValue = '';
        newValue = formatTimeDisplay(newValue, fieldDef?.timeFormat);
      } else {
        const rawValue = (reportData as any)[fieldKey];
        if (Array.isArray(rawValue)) {
          newValue = rawValue.join(', ');
        } else if (rawValue !== undefined && rawValue !== null) {
          newValue = String(rawValue);
        }
        if (fieldDef?.type === 'date') {
          newValue = formatDateDisplay(newValue, fieldDef.timeFormat);
        } else if (fieldDef?.type === 'time') {
          newValue = formatTimeDisplay(newValue, fieldDef.timeFormat);
        }
      }

      if (el.innerText !== newValue) {
        el.innerText = newValue;
      }
    });
  }, [reportData]);

  if (!currentUser) return null;

  const hasVisibleTemplates = templates.length > 0;

  return (
    <div className="flex h-screen bg-bg overflow-hidden">
      <Sidebar />
      
      <div className="flex-1 flex flex-col overflow-hidden">
        {/* Header */}
        <header className="h-20 bg-white border-b border-border flex items-center justify-between px-8 shrink-0">
          <div className="flex items-center gap-4">
            <button 
              onClick={() => navigate('/report-manage')}
              className="p-2 rounded-lg hover:bg-slate-100 text-text-muted transition-colors"
            >
              <ChevronLeft size={24} />
            </button>
            <div>
              <h1 className="text-lg font-bold text-text-main">图文报告生成</h1>
              <p className="text-[10px] text-text-muted mt-0.5 uppercase tracking-wider font-bold">
                {reportId ? `编辑报告: ${reportId}` : '新建手术报告'}
              </p>
            </div>
          </div>
          <div className="flex items-center gap-4">
            <div className="flex items-center gap-1">
              <span className="text-xs text-text-muted whitespace-nowrap">当前模板（及重置模板）：</span>
              <select 
                value=""
                onChange={(e) => {
                  const tplId = e.target.value;
                  const tpl = templates.find(t => t.id === tplId);
                  if (tpl && window.confirm(`确定要应用模板 "${tpl.name}" 吗？当前内容、基本信息、视频分析将被重置。`)) {
                    setPendingTemplateId(tplId);
                  }
                }}
                className="h-8 px-2 border border-border rounded-lg text-xs bg-white cursor-pointer focus:outline-hidden focus:border-accent"
              >
                <option value="" disabled>
                  {templates.find(t => t.id === loadedTemplateId)?.name || '无'}
                </option>
                {templates.map(tpl => (
                  <option key={tpl.id} value={tpl.id}>{tpl.name}</option>
                ))}
              </select>
            </div>
            {isSaved && (
              <span className="text-xs text-green-600 font-bold flex items-center gap-1">
                <Check size={14} />
                已保存
              </span>
            )}
            <button 
              onClick={() => saveReport('draft')}
              className="px-6 py-2.5 bg-slate-100 text-text-muted rounded-lg text-sm font-semibold hover:bg-slate-200 transition-colors"
            >
              保存草稿
            </button>
            <button 
              onClick={() => saveReport('completed')}
              className="btn-accent inline-flex items-center gap-2"
            >
              <Check size={16} />
              完成报告
            </button>
            <button 
              onClick={() => setExportModalOpen(true)}
              className="p-2.5 rounded-lg bg-slate-100 text-text-muted hover:bg-slate-200 transition-colors"
              title="下载"
            >
              <Download size={18} />
            </button>
            <button 
              onClick={() => editorRef.current && printDocument(editorRef.current.innerHTML)}
              className="p-2.5 rounded-lg bg-slate-100 text-text-muted hover:bg-slate-200 transition-colors"
            >
              <Printer size={18} />
            </button>
          </div>
        </header>

        <div className="flex-1 flex overflow-hidden">
          {/* Editor Main */}
          <div className="flex-1 flex flex-col overflow-hidden border-r border-border">
            {/* Toolbar */}
            <div className="flex items-center gap-1 p-3 border-b border-border bg-slate-50 shrink-0 overflow-x-auto no-scrollbar">
              <div className="flex gap-1 pr-3 mr-3 border-r border-border">
                <button onClick={() => execCmd('undo')} className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-white text-text-muted hover:text-text-main transition-colors" title="撤销"><Undo size={16} /></button>
                <button onClick={() => execCmd('redo')} className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-white text-text-muted hover:text-text-main transition-colors" title="重做"><Redo size={16} /></button>
              </div>
              <div className="flex gap-1 pr-3 mr-3 border-r border-border">
                <select 
                  onMouseDown={(e) => e.preventDefault()}
                  onChange={(e) => { execCmd('fontName', e.target.value); e.target.value = ''; }}
                  className="h-9 px-3 border border-border rounded-lg text-xs bg-white cursor-pointer focus:outline-hidden focus:border-accent"
                >
                  <option value="">字体</option>
                  <option value="SimSun">宋体</option>
                  <option value="Microsoft YaHei">微软雅黑</option>
                  <option value="SimHei">黑体</option>
                  <option value="KaiTi">楷体</option>
                </select>
                <select
                  onMouseDown={(e) => e.preventDefault()}
                  onChange={(e) => { if (e.target.value) { execCmd('fontSize', e.target.value); } e.target.value = ''; }}
                  className="h-9 px-3 border border-border rounded-lg text-xs bg-white cursor-pointer focus:outline-hidden focus:border-accent"
                >
                  <option value="">字号</option>
                  <option value="3">12pt</option>
                  <option value="4">14pt</option>
                  <option value="5">18pt</option>
                  <option value="6">24pt</option>
                </select>
                <select
                  onMouseDown={(e) => e.preventDefault()}
                  onChange={(e) => { if (e.target.value) { changeLineHeight(e.target.value); } e.target.value = ''; }}
                  className="h-9 px-3 border border-border rounded-lg text-xs bg-white cursor-pointer focus:outline-hidden focus:border-accent"
                >
                  <option value="">行距</option>
                  <option value="1">1.0</option>
                  <option value="1.5">1.5</option>
                  <option value="2">2.0</option>
                </select>
              </div>
              <div className="flex gap-1 pr-3 mr-3 border-r border-border">
                <button onClick={() => execCmd('bold')} className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-white text-text-muted hover:text-text-main transition-colors" title="粗体"><Bold size={16} /></button>
                <button onClick={() => execCmd('italic')} className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-white text-text-muted hover:text-text-main transition-colors" title="斜体"><Italic size={16} /></button>
                <button onClick={() => execCmd('underline')} className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-white text-text-muted hover:text-text-main transition-colors" title="下划线"><Underline size={16} /></button>
                <div className="relative flex items-center">
                  <input 
                    type="color" 
                    onChange={(e) => execCmd('foreColor', e.target.value)}
                    className="w-9 h-9 p-1.5 bg-transparent border-none cursor-pointer rounded-lg hover:bg-white transition-colors"
                    title="文字颜色"
                  />
                </div>
              </div>
              <div className="flex gap-1 pr-3 mr-3 border-r border-border">
                <button onClick={() => execCmd('justifyLeft')} className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-white text-text-muted hover:text-text-main transition-colors" title="左对齐"><AlignLeft size={16} /></button>
                <button onClick={() => execCmd('justifyCenter')} className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-white text-text-muted hover:text-text-main transition-colors" title="居中"><AlignCenter size={16} /></button>
                <button onClick={() => execCmd('justifyRight')} className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-white text-text-muted hover:text-text-main transition-colors" title="右对齐"><AlignRight size={16} /></button>
              </div>
              <div className="flex gap-1">
                <button onClick={insertTable} className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-white text-text-muted hover:text-text-main transition-colors" title="表格"><Table size={16} /></button>
                <button onClick={insertImage} className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-white text-text-muted hover:text-text-main transition-colors" title="插入图片占位符"><ImageIcon size={16} /></button>
              </div>
            </div>

            {/* Editor Content */}
            <div 
              className="editor-content-wrapper print-wrapper"
              onDragOver={(e) => e.preventDefault()}
              onDrop={(e) => {
                const target = e.target as HTMLElement;
                const placeholder = target.closest('.image-placeholder') as HTMLElement;
                if (placeholder) handleDrop(e, placeholder);
              }}
            >
              <div 
                ref={editorRef}
                contentEditable
                onInput={handleEditorInput}
                onBlur={() => { contentRef.current = editorRef.current?.innerHTML || ''; saveDraftToStorage(); }}
                className="editor-content print-content"
              >
              </div>
            </div>
          </div>

          {/* Right Sidebar */}
          <aside className="w-[380px] bg-sidebar-bg flex flex-col shrink-0 overflow-hidden">
            <div className="flex border-b border-border">
              {(['info', 'video'] as const).map(tab => (
                <button 
                  key={tab}
                  onClick={() => { setActiveTab(tab); stateRef.current = { ...stateRef.current, activeTab: tab }; saveDraftToStorage(); }}
                  className={`flex-1 py-4 text-xs font-bold transition-all border-b-2 uppercase tracking-wider ${
                    activeTab === tab ? 'text-accent border-accent' : 'text-text-muted border-transparent hover:text-text-main'
                  }`}
                >
                  {tab === 'info' ? '基本信息' : '视频分析'}
                </button>
              ))}
            </div>

            <div className="flex-1 overflow-y-auto p-6 space-y-8">
              {activeTab === 'info' && (
                <div className="report-info-form space-y-4">
                  {(() => {
                    const topKeys = ['patientName', 'hospitalId', 'title'];
                    const contentHtml = contentRef.current || editorRef.current?.innerHTML || '';
                    return [...formFields.filter(f => f.visibleInForm)].sort((a, b) => {
                      const aTop = topKeys.indexOf(a.key);
                      const bTop = topKeys.indexOf(b.key);
                      if (aTop !== -1 && bTop !== -1) return aTop - bTop;
                      if (aTop !== -1) return -1;
                      if (bTop !== -1) return 1;
                      const aIndex = contentHtml.indexOf(`data-bind="${a.key}"`);
                      const bIndex = contentHtml.indexOf(`data-bind="${b.key}"`);
                      if (aIndex === -1 && bIndex === -1) return 0;
                      if (aIndex === -1) return 1;
                      if (bIndex === -1) return -1;
                      return aIndex - bIndex;
                    });
                  })().map(field => {
                    const isRequired = field.isSystemLocked;
                    const hasError = isRequired && touched[field.key] && !(reportData as any)[field.key];

                    if (field.type === 'text' || field.type === 'date') {
                      const inputType = field.type === 'date' ? 'date' : 'text';
                      return (
                        <div key={field.key} id={`input-${field.key}`} className={field.category === '填空' && formFields.filter(f2 => f2.visibleInForm && f2.type === 'text' && f2.isSystemLocked).length > 1 && (field.key === 'patientName' || field.key === 'hospitalId') ? 'flex-1 space-y-1' : 'space-y-1'}>
                          <label className="block text-xs font-bold text-text-main">
                            {field.label} {isRequired && <span className="text-red-500">*</span>}
                          </label>
                          <input
                            type={inputType}
                            value={(reportData as any)[field.key] || ''}
                            onChange={(e) => { const next = { ...reportData, [field.key]: e.target.value }; setReportData(next); stateRef.current = { ...stateRef.current, reportData: next }; saveDraftToStorage(); }}
                            onBlur={() => setTouched(t => ({ ...t, [field.key]: true }))}
                            className={`input-minimal ${hasError ? 'border-red-500' : ''}`}
                            placeholder={field.label}
                          />
                        </div>
                      );
                    }

                    if (field.type === 'single_select') {
                      const isOpen = openDropdown === field.key;
                      const opts = field.options || (field.key === 'anesthesiaType' ? anesthesiaOptions : []);
                      return (
                        <div key={field.key} id={`input-${field.key}`} className="space-y-1 select-dropdown-root relative">
                          <label className="block text-xs font-bold text-text-main">{field.label}</label>
                          <div
                            className="w-full px-3 py-2 border border-border rounded-lg bg-white flex items-center min-h-[42px] cursor-text"
                            onClick={() => setOpenDropdown(field.key)}
                          >
                            <input
                              type="text"
                              className="outline-none text-sm flex-1 bg-transparent"
                              placeholder={`输入或选择${field.label}`}
                              value={(reportData as any)[field.key] || ''}
                              onChange={(e) => { const next = { ...reportData, [field.key]: e.target.value }; setReportData(next); stateRef.current = { ...stateRef.current, reportData: next }; saveDraftToStorage(); }}
                              onFocus={() => setOpenDropdown(field.key)}
                              onKeyDown={(e) => {
                                if (e.key === 'Enter') {
                                  e.preventDefault();
                                  const val = (e.target as HTMLInputElement).value.trim();
                                  if (val) {
                                    const next = { ...reportData, [field.key]: val };
                                    setReportData(next);
                                    stateRef.current = { ...stateRef.current, reportData: next };
                                    saveDraftToStorage();
                                    if (!opts.includes(val)) {
                                      const updatedOpts = [...opts, val];
                                      if (field.key === 'anesthesiaType') {
                                        setAnesthesiaOptions(updatedOpts);
                                        storage.set('anesthesiaOptions', updatedOpts);
                                      }
                                      const updatedFields = formFields.map(f => f.key === field.key ? { ...f, options: updatedOpts } : f);
                                      setFormFields(updatedFields);
                                      storage.set('formFieldsConfig', updatedFields);
                                    }
                                    setOpenDropdown(null);
                                  }
                                }
                              }}
                            />
                          </div>
                          {isOpen && (
                            <div className="absolute z-10 left-0 right-0 top-full mt-1 bg-white border border-border rounded-lg shadow-lg max-h-[150px] overflow-y-auto">
                              {opts.map(opt => (
                                <div
                                  key={opt}
                                  className="px-3 py-2 text-sm hover:bg-slate-50 cursor-pointer flex justify-between items-center"
                                  onClick={() => { const next = { ...reportData, [field.key]: opt }; setReportData(next); stateRef.current = { ...stateRef.current, reportData: next }; saveDraftToStorage(); setOpenDropdown(null); }}
                                >
                                  <span>{opt}</span>
                                  <span
                                    className="text-red-500 text-xs hover:bg-red-50 px-1 rounded"
                                    onClick={(e) => {
                                      e.stopPropagation();
                                      const updatedOpts = opts.filter(v => v !== opt);
                                      if (field.key === 'anesthesiaType') {
                                        setAnesthesiaOptions(updatedOpts);
                                        storage.set('anesthesiaOptions', updatedOpts);
                                      }
                                      const updatedFields = formFields.map(f => f.key === field.key ? { ...f, options: updatedOpts } : f);
                                      setFormFields(updatedFields);
                                      storage.set('formFieldsConfig', updatedFields);
                                    }}
                                  >×</span>
                                </div>
                              ))}
                              {opts.length === 0 && (
                                <div className="px-3 py-2 text-xs text-text-muted">暂无选项</div>
                              )}
                            </div>
                          )}
                        </div>
                      );
                    }

                    if (field.type === 'multi_select') {
                      const isOpen = openDropdown === field.key;
                      const opts = field.options || multiSelectOptions[field.key] || [];
                      const rawValue = (reportData as any)[field.key];
                      const currentValues = Array.isArray(rawValue) ? rawValue : (rawValue ? [String(rawValue)] : []);
                      const displayText = currentValues.join(', ');

                      const parseMultiInput = (text: string): string[] => {
                        return Array.from(new Set(text.split(/[,，;；、]/).map(s => s.trim()).filter(Boolean)));
                      };

                      const handleMultiCommit = (text: string) => {
                        const values = parseMultiInput(text);
                        const next = { ...reportData, [field.key]: values };
                        setReportData(next);
                        stateRef.current = { ...stateRef.current, reportData: next };
                        saveDraftToStorage();

                        const currentOpts = field.options || multiSelectOptions[field.key] || [];
                        const newOpts = values.filter(v => !currentOpts.includes(v));
                        if (newOpts.length > 0) {
                          const mergedOpts = [...currentOpts, ...newOpts];
                          const nextMulti = { ...multiSelectOptions, [field.key]: mergedOpts };
                          setMultiSelectOptions(nextMulti);
                          storage.set('multiSelectOptions', nextMulti);
                          const fieldDef = formFields.find(f => f.key === field.key);
                          if (fieldDef) {
                            const updatedFields = formFields.map(f => f.key === field.key ? { ...f, options: mergedOpts } : f);
                            setFormFields(updatedFields);
                            storage.set('formFieldsConfig', updatedFields);
                          }
                        }
                      };

                      const currentInputText = multiInputText[field.key] !== undefined ? multiInputText[field.key] : displayText;

                      return (
                        <div key={field.key} id={`input-${field.key}`} className="space-y-1 select-dropdown-root relative">
                          <label className="block text-xs font-bold text-text-main">{field.label}（可多选）</label>
                          <div
                            className="w-full px-3 py-2 border border-border rounded-lg bg-white flex flex-wrap gap-1 items-center min-h-[42px] cursor-text"
                            onClick={() => setOpenDropdown(field.key)}
                          >
                            <input
                              type="text"
                              className="outline-none text-sm w-full bg-transparent"
                              placeholder="输入或选择，多个用逗号分隔"
                              value={currentInputText}
                              onChange={(e) => {
                                setMultiInputText(prev => ({ ...prev, [field.key]: e.target.value }));
                              }}
                              onFocus={() => setOpenDropdown(field.key)}
                              onBlur={(e) => {
                                handleMultiCommit(e.target.value);
                                setMultiInputText(prev => {
                                  const next = { ...prev };
                                  delete next[field.key];
                                  return next;
                                });
                              }}
                              onKeyDown={(e) => {
                                if (e.key === 'Enter') {
                                  e.preventDefault();
                                  handleMultiCommit((e.target as HTMLInputElement).value);
                                  setMultiInputText(prev => {
                                    const next = { ...prev };
                                    delete next[field.key];
                                    return next;
                                  });
                                }
                              }}
                            />
                          </div>
                          {isOpen && (
                            <div className="absolute z-10 left-0 right-0 top-full mt-1 bg-white border border-border rounded-lg shadow-lg max-h-[150px] overflow-y-auto">
                              {opts.map(opt => (
                                <div
                                  key={opt}
                                  className="px-3 py-2 text-sm hover:bg-slate-50 cursor-pointer flex justify-between items-center"
                                  onClick={() => {
                                    const base = multiInputText[field.key] !== undefined ? multiInputText[field.key] : displayText;
                                    const newText = base.length > 0 ? `${base}, ${opt}` : opt;
                                    setMultiInputText(prev => ({ ...prev, [field.key]: newText }));
                                    handleMultiCommit(newText);
                                    setMultiInputText(prev => {
                                      const next = { ...prev };
                                      delete next[field.key];
                                      return next;
                                    });
                                  }}
                                >
                                  <span>{opt}</span>
                                  <span
                                    className="text-red-500 text-xs hover:bg-red-50 px-1 rounded"
                                    onClick={(e) => { e.stopPropagation(); removeMultiOption(field.key, opt); }}
                                  >×</span>
                                </div>
                              ))}
                              {opts.length === 0 && (
                                <div className="px-3 py-2 text-xs text-text-muted">暂无选项</div>
                              )}
                            </div>
                          )}
                        </div>
                      );
                    }

                    if (field.type === 'time') {
                      const is12h = field.timeFormat ? (field.timeFormat.includes('hh') || field.timeFormat.includes('A')) : false;

                      if (field.key === 'startTime' || field.key === 'endTime') {
                        const hourKey = field.key === 'startTime' ? 'startHour' : 'endHour';
                        const minuteKey = field.key === 'startTime' ? 'startMinute' : 'endMinute';
                        const h24val = parseInt((reportData as any)[hourKey]) || 0;
                        const m = (reportData as any)[minuteKey] || '';
                        const { h: h12, isPM } = from24h(h24val);

                        return (
                          <div key={field.key} id={`input-${field.key}`} className="space-y-1">
                            <label className="block text-xs font-bold text-text-main">{field.label}</label>
                            <div className="flex items-center gap-2">
                              <select
                                value={is12h ? String(h12).padStart(2, '0') : ((reportData as any)[hourKey] || '')}
                                onChange={(e) => {
                                  let h24new = parseInt(e.target.value) || 0;
                                  if (is12h) {
                                    const currentPM = from24h(parseInt((reportData as any)[hourKey]) || 0).isPM;
                                    h24new = to24h(h24new, currentPM);
                                  }
                                  const next = { ...reportData, [hourKey]: String(h24new).padStart(2, '0') };
                                  setReportData(next); stateRef.current = { ...stateRef.current, reportData: next }; saveDraftToStorage();
                                }}
                                className="input-minimal bg-white flex-1"
                              >
                                <option value="">--</option>
                                {(is12h ? hour12Options : hourOptions).map(h => <option key={h} value={h}>{h}</option>)}
                              </select>
                              <span className="text-text-muted">:</span>
                              <select
                                value={m}
                                onChange={(e) => { const next = { ...reportData, [minuteKey]: e.target.value }; setReportData(next); stateRef.current = { ...stateRef.current, reportData: next }; saveDraftToStorage(); }}
                                className="input-minimal bg-white flex-1"
                              >
                                <option value="">--</option>
                                {minuteOptions.map(mo => <option key={mo} value={mo}>{mo}</option>)}
                              </select>
                              {is12h && (
                                <select
                                  value={isPM ? '下午' : '上午'}
                                  onChange={(e) => {
                                    const isPMnew = e.target.value === '下午';
                                    const currentH12 = from24h(parseInt((reportData as any)[hourKey]) || 0).h;
                                    const h24new = to24h(currentH12, isPMnew);
                                    const next = { ...reportData, [hourKey]: String(h24new).padStart(2, '0') };
                                    setReportData(next); stateRef.current = { ...stateRef.current, reportData: next }; saveDraftToStorage();
                                  }}
                                  className="input-minimal bg-white flex-1"
                                >
                                  <option value="上午">上午</option>
                                  <option value="下午">下午</option>
                                </select>
                              )}
                            </div>
                          </div>
                        );
                      }

                      // 通用 time 字段
                      const timeVal = (reportData as any)[field.key] || '';
                      const [h24str, mstr] = timeVal.split(':');
                      const h24 = parseInt(h24str) || 0;
                      const m = mstr || '';
                      const { h: h12g, isPM: isPMg } = from24h(h24);

                      return (
                        <div key={field.key} id={`input-${field.key}`} className="space-y-1">
                          <label className="block text-xs font-bold text-text-main">{field.label}</label>
                          <div className="flex items-center gap-2">
                            <select
                              value={is12h ? String(h12g).padStart(2, '0') : (h24str || '')}
                              onChange={(e) => {
                                let h24new = parseInt(e.target.value) || 0;
                                if (is12h) h24new = to24h(h24new, isPMg);
                                const nextVal = `${String(h24new).padStart(2, '0')}:${m || '00'}`;
                                const next = { ...reportData, [field.key]: nextVal };
                                setReportData(next); stateRef.current = { ...stateRef.current, reportData: next }; saveDraftToStorage();
                              }}
                              className="input-minimal bg-white flex-1"
                            >
                              <option value="">--</option>
                              {(is12h ? hour12Options : hourOptions).map(h => <option key={h} value={h}>{h}</option>)}
                            </select>
                            <span className="text-text-muted">:</span>
                            <select
                              value={m}
                              onChange={(e) => {
                                const nextVal = `${String(h24).padStart(2, '0')}:${e.target.value}`;
                                const next = { ...reportData, [field.key]: nextVal };
                                setReportData(next); stateRef.current = { ...stateRef.current, reportData: next }; saveDraftToStorage();
                              }}
                              className="input-minimal bg-white flex-1"
                            >
                              <option value="">--</option>
                              {minuteOptions.map(mo => <option key={mo} value={mo}>{mo}</option>)}
                            </select>
                            {is12h && (
                              <select
                                value={isPMg ? '下午' : '上午'}
                                onChange={(e) => {
                                  const isPMnew = e.target.value === '下午';
                                  const h24new = to24h(h12g, isPMnew);
                                  const nextVal = `${String(h24new).padStart(2, '0')}:${m || '00'}`;
                                  const next = { ...reportData, [field.key]: nextVal };
                                  setReportData(next); stateRef.current = { ...stateRef.current, reportData: next }; saveDraftToStorage();
                                }}
                                className="input-minimal bg-white flex-1"
                              >
                                <option value="上午">上午</option>
                                <option value="下午">下午</option>
                              </select>
                            )}
                          </div>
                        </div>
                      );
                    }

                    return null;
                  })}
                </div>
              )}

              {activeTab === 'video' && (
                <div className="space-y-4">
                  <input 
                    ref={videoInputRef}
                    type="file" 
                    accept="video/*" 
                    multiple 
                    className="hidden" 
                    onChange={handleVideoUpload} 
                  />
                  <button
                    onClick={() => videoInputRef.current?.click()}
                    className="w-full flex items-center justify-center gap-2 p-3 border border-dashed border-border rounded-lg hover:border-accent hover:bg-slate-50 transition-all"
                  >
                    <Video size={18} />
                    <div className="text-left">
                      <p className="text-xs font-bold text-text-main">点击上传手术视频</p>
                      <p className="text-[10px] text-text-muted">支持 MP4, MOV 格式</p>
                    </div>
                  </button>

                  {videos.length > 0 && (
                    <div className="space-y-4">
                      <div className="flex gap-2 overflow-x-auto pb-2 no-scrollbar">
                        {videos.map((v, i) => (
                          <div 
                            key={v.id}
                            className={`shrink-0 w-24 p-1.5 border-2 rounded-xl cursor-pointer transition-all relative group ${
                              currentVideoIndex === i ? 'border-accent bg-white shadow-sm' : 'border-transparent'
                            }`}
                          >
                            <div 
                              onClick={() => selectVideo(i)}
                              className="aspect-video bg-slate-900 rounded-lg flex items-center justify-center text-white"
                            >
                              <Play size={16} />
                            </div>
                            <div 
                              onClick={() => selectVideo(i)}
                              className="text-[9px] font-bold text-text-main truncate mt-1.5 px-1"
                            >{v.name}</div>
                            <button
                              onClick={() => removeVideo(v.id)}
                              className="absolute -top-2 -right-2 w-5 h-5 bg-red-500 text-white rounded-full flex items-center justify-center text-[10px] opacity-0 group-hover:opacity-100 transition-all shadow-sm"
                            >
                              <X size={12} />
                            </button>
                          </div>
                        ))}
                      </div>

                      {currentVideoIndex !== -1 && (
                        <div className="space-y-4">
                          <div className="relative bg-slate-900 rounded-2xl overflow-hidden aspect-video shadow-lg">
                            <video 
                              ref={videoRef}
                              src={videos[currentVideoIndex].url}
                              className="w-full h-full"
                              onTimeUpdate={() => setCurrentTime(videoRef.current?.currentTime || 0)}
                              onLoadedMetadata={() => {
                                const dur = videoRef.current?.duration || 0;
                                setDuration(dur);
                                setVideos(prev => prev.map((v, i) => i === currentVideoIndex ? { ...v, duration: dur } : v));
                              }}
                            />
                            {!isPlaying && (
                              <div className="absolute inset-0 flex items-center justify-center bg-black/40 cursor-pointer" onClick={togglePlay}>
                                <div className="w-16 h-16 rounded-full bg-white/20 backdrop-blur-md flex items-center justify-center text-white">
                                  <Play size={32} fill="currentColor" />
                                </div>
                              </div>
                            )}
                            <div className="absolute bottom-4 right-4 bg-black/60 backdrop-blur-md text-white text-[10px] font-bold px-3 py-1.5 rounded-full">
                              {formatTime(currentTime)} / {formatTime(duration)}
                            </div>
                          </div>
                          
                          <div className="flex items-center gap-4">
                            <button onClick={togglePlay} className="w-10 h-10 flex items-center justify-center bg-slate-100 rounded-xl text-text-main hover:bg-slate-200 transition-colors">
                              {isPlaying ? <Pause size={18} /> : <Play size={18} />}
                            </button>
                            <div className="flex-1 h-2 bg-slate-100 rounded-full overflow-hidden cursor-pointer relative" onClick={(e) => {
                              const rect = e.currentTarget.getBoundingClientRect();
                              const pos = (e.clientX - rect.left) / rect.width;
                              if (videoRef.current) videoRef.current.currentTime = pos * duration;
                            }}>
                              <div className="h-full bg-accent" style={{ width: `${(currentTime / duration) * 100}%` }} />
                            </div>
                          </div>

                          <div className="flex justify-between items-center pt-2">
                            <span className="text-[10px] font-bold text-text-main uppercase tracking-wider">关键帧摘取</span>
                            <button 
                              onClick={captureFrame} 
                              className="px-4 py-2 bg-accent text-white rounded-lg text-[10px] font-bold uppercase tracking-wider hover:bg-blue-700 transition-colors shadow-sm"
                            >
                              截取当前帧
                            </button>
                          </div>

                          <div className="grid grid-cols-2 gap-3 max-h-[400px] overflow-y-auto pr-2 custom-scrollbar">
                            {capturedFrames.filter(f => f.videoIndex === currentVideoIndex).map((frame) => (
                              <div 
                                key={frame.id}
                                draggable
                                onDragStart={(e) => handleDragStart(e, frame)}
                                onClick={() => seekToFrame(frame)}
                                className={`group relative card-minimal p-1 border-2 cursor-grab active:cursor-grabbing hover:shadow-md transition-all ${
                                  frame.isManual ? 'border-yellow-400 hover:border-yellow-500' : 'border-transparent hover:border-accent'
                                }`}
                              >
                                <div className="relative">
                                  <img src={frame.dataUrl} className="w-full aspect-video object-cover rounded-lg" />
                                  {frame.isManual && <span className="manual-frame-badge">手动</span>}
                                </div>
                                <div className="text-[9px] font-bold text-text-muted mt-1.5 px-1 flex justify-between items-center">
                                  <span>{frame.timeFormatted}</span>
                                  <div className="flex items-center gap-2">
                                    <button
                                      onClick={(e) => { e.stopPropagation(); insertFrameToPlaceholder(frame); }}
                                      className="px-2 py-0.5 bg-accent text-white text-[9px] font-bold rounded-full shadow-sm opacity-0 group-hover:opacity-100 transition-opacity hover:bg-blue-700"
                                    >
                                      插入
                                    </button>
                                    <span className="text-accent opacity-0 group-hover:opacity-100 transition-opacity">可拖拽</span>
                                  </div>
                                </div>
                                <button 
                                  onClick={(e) => { e.stopPropagation(); setCapturedFrames(prev => prev.filter(f => f.id !== frame.id).sort((a, b) => a.time - b.time)); saveDraftToStorage(); }}
                                  className="absolute -top-2 -right-2 w-6 h-6 bg-red-500 text-white rounded-full flex items-center justify-center text-xs opacity-0 group-hover:opacity-100 transition-all shadow-md"
                                >
                                  <X size={14} />
                                </button>
                              </div>
                            ))}
                          </div>
                          <p className="text-[10px] text-text-muted text-center">
                            提示：点击关键帧可跳转视频位置，按键盘 ← → 键可微调进度
                          </p>
                        </div>
                      )}
                    </div>
                  )}
                </div>
              )}
            </div>
          </aside>
        </div>
      </div>
      <canvas ref={canvasRef} className="hidden" />

      {placeholderModal.isOpen && (
        <div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
          <div className="bg-white rounded-2xl p-6 w-full max-w-[360px] shadow-2xl border border-border">
            <h3 className="text-lg font-bold text-text-main mb-4">插入图片占位符</h3>
            <div className="space-y-3">
              <div className="flex gap-2">
                <div className="flex-1">
                  <label className="block text-xs mb-1">宽度(px)</label>
                  <input type="number" value={placeholderModal.width} onChange={e => setPlaceholderModal({...placeholderModal, width: e.target.value})} className="w-full px-2 py-1 text-xs border border-border rounded" />
                </div>
                <div className="flex-1">
                  <label className="block text-xs mb-1">高度(px)</label>
                  <input type="number" value={placeholderModal.height} onChange={e => setPlaceholderModal({...placeholderModal, height: e.target.value})} className="w-full px-2 py-1 text-xs border border-border rounded" />
                </div>
              </div>
              <div>
                <label className="block text-xs mb-1">占位符类型</label>
                <div className="flex gap-2">
                  <button onClick={() => setPlaceholderModal({...placeholderModal, mode: 'frame'})} className={`flex-1 py-1.5 text-xs rounded border ${placeholderModal.mode === 'frame' ? 'bg-accent text-white border-accent' : 'bg-white text-slate-600 border-border'}`}>手术影像占位<br/><span className="text-[10px] opacity-80">（支持自动/拖拽插入）</span></button>
                  <button onClick={() => setPlaceholderModal({...placeholderModal, mode: 'manual'})} className={`flex-1 py-1.5 text-xs rounded border ${placeholderModal.mode === 'manual' ? 'bg-accent text-white border-accent' : 'bg-white text-slate-600 border-border'}`}>静态图片占位<br/><span className="text-[10px] opacity-80">（仅支持点击插入）</span></button>
                </div>
              </div>
            </div>
            <div className="mt-5 flex justify-end gap-2">
              <button onClick={() => setPlaceholderModal({...placeholderModal, isOpen: false})} className="px-4 py-2 bg-slate-100 text-slate-600 rounded text-sm">取消</button>
              <button onClick={() => {
                const sel = window.getSelection();
                let node: Node | null = sel?.anchorNode ?? null;
                let inTable = false;
                while (node) {
                  if ((node as Element).nodeName === 'TD' || (node as Element).nodeName === 'TH') {
                    inTable = true;
                    break;
                  }
                  node = node.parentNode;
                }
                const w = parseInt(placeholderModal.width) || 200;
                const h = parseInt(placeholderModal.height) || 200;
                const modeAttr = placeholderModal.mode === 'manual' ? ' data-mode="manual"' : '';
                const hintText = '插入/点击放置图片';
                const id = 'ph_' + Date.now();
                let html: string;
                if (inTable) {
                  const styleStr = 'display:flex;align-items:center;justify-content:center;border:1px dashed #cbd5e1;background:#f8fafc;cursor:pointer;width:100%;height:100%;max-width:200px;max-height:200px;min-height:60px;margin:0 auto;';
                  html = `<div id="${id}" class="image-placeholder" data-placeholder="true" contenteditable="false"${modeAttr} style="${styleStr}"><span class="delete-btn" contenteditable="false">×</span><span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;">${hintText}</span></div>`;
                } else {
                  let styleStr = 'display:inline-block;text-align:center;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;margin:0 4px;cursor:pointer;position:relative;';
                  styleStr += `width:${w}px;height:${h}px;line-height:${h}px;`;
                  const showShortText = w > 0 && w < 80;
                  const text = showShortText ? '插图' : hintText;
                  html = `<span id="${id}" class="image-placeholder" data-placeholder="true" contenteditable="false"${modeAttr} style="${styleStr}"><span class="delete-btn" contenteditable="false">×</span><span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;display:inline-block;vertical-align:middle;line-height:normal;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">${text}</span></span>&#8203;`;
                }
                execCmd('insertHTML', html);
                setPlaceholderModal({...placeholderModal, isOpen: false});
              }} className="px-4 py-2 bg-accent text-white rounded text-sm">确认插入</button>
            </div>
          </div>
        </div>
      )}

      {tableModal.isOpen && (
        <div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
          <div className="bg-white rounded-2xl p-6 w-full max-w-[360px] shadow-2xl border border-border">
            <h3 className="text-lg font-bold text-text-main mb-4">插入表格</h3>
            <div className="space-y-3">
              <div className="flex gap-2">
                <div className="flex-1">
                  <label className="block text-xs mb-1">行数</label>
                  <input type="number" min="1" value={tableModal.rows} onChange={e => setTableModal({...tableModal, rows: e.target.value})} className="w-full px-2 py-1 text-xs border border-border rounded" />
                </div>
                <div className="flex-1">
                  <label className="block text-xs mb-1">列数</label>
                  <input type="number" min="1" value={tableModal.cols} onChange={e => setTableModal({...tableModal, cols: e.target.value})} className="w-full px-2 py-1 text-xs border border-border rounded" />
                </div>
              </div>
            </div>
            <div className="mt-5 flex justify-end gap-2">
              <button onClick={() => setTableModal({...tableModal, isOpen: false})} className="px-4 py-2 bg-slate-100 text-slate-600 rounded text-sm">取消</button>
              <button onClick={() => {
                const rows = parseInt(tableModal.rows);
                const cols = parseInt(tableModal.cols);
                if (isNaN(rows) || isNaN(cols) || rows < 1 || cols < 1) {
                  setTableModal({...tableModal, isOpen: false});
                  return;
                }
                let table = '<table style="width: 100%; border-collapse: collapse; margin: 16px 0; table-layout: fixed;">';
                for (let i = 0; i < rows; i++) {
                  table += '<tr>';
                  for (let j = 0; j < cols; j++) {
                    table += '<td style="padding: 8px; border: 1px solid #e2e8f0; vertical-align: top;">单元格</td>';
                  }
                  table += '</tr>';
                }
                table += '</table><p></p>';
                execCmd('insertHTML', table);
                setTableModal({...tableModal, isOpen: false});
              }} className="px-4 py-2 bg-accent text-white rounded text-sm">确认插入</button>
            </div>
          </div>
        </div>
      )}

      {exportModalOpen && (
        <div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
          <div className="bg-white rounded-2xl p-6 w-full max-w-[360px] shadow-2xl border border-border">
            <h3 className="text-lg font-bold text-text-main mb-4">导出报告</h3>
            <div className="space-y-3">
              <button
                onClick={() => {
                  const ts = new Date().toISOString().replace(/[:.]/g, '-');
                  const title = reportData.title || '无标题';
                  const patient = reportData.patientName || '未知';
                  const hid = reportData.hospitalId || '无号';
                  printDocument(editorRef.current?.innerHTML || '', `图文报告-${title}-${patient}-${hid}-${ts}`);
                  setExportModalOpen(false);
                }}
                className="w-full py-2.5 bg-accent text-white rounded text-sm font-semibold hover:opacity-90 transition-colors"
              >导出 PDF</button>
              <button
                onClick={() => {
                  const ts = new Date().toISOString().replace(/[:.]/g, '-');
                  const title = reportData.title || '无标题';
                  const patient = reportData.patientName || '未知';
                  const hid = reportData.hospitalId || '无号';
                  const blob = new Blob([JSON.stringify(reportData, null, 2)], { type: 'application/json' });
                  const url = URL.createObjectURL(blob);
                  const a = document.createElement('a');
                  a.href = url;
                  a.download = `图文报告-${title}-${patient}-${hid}-${ts}.json`;
                  a.click();
                  URL.revokeObjectURL(url);
                  setExportModalOpen(false);
                }}
                className="w-full py-2.5 bg-slate-100 text-slate-700 rounded text-sm font-semibold hover:bg-slate-200 transition-colors"
              >导出 JSON</button>
              <button
                onClick={() => setExportModalOpen(false)}
                className="w-full py-2.5 border border-border text-text-main rounded text-sm font-semibold hover:bg-slate-50 transition-colors"
              >取消</button>
            </div>
          </div>
        </div>
      )}

      {imagePickerOpen && imagePickerTarget && (
        <div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
          <div className="bg-white rounded-2xl p-6 w-full max-w-[360px] shadow-2xl border border-border">
            <h3 className="text-lg font-bold text-text-main mb-4">选择图片来源</h3>
            <div className="space-y-3">
              <button
                onClick={() => {
                  const input = document.createElement('input');
                  input.type = 'file';
                  input.accept = 'image/*';
                  input.onchange = (ev) => {
                    const file = (ev.target as HTMLInputElement).files?.[0];
                    if (file) {
                      const reader = new FileReader();
                      reader.onload = (event) => {
                        const src = event.target?.result as string;
                        fillPlaceholderSrc(imagePickerTarget, src);
                        setImagePickerOpen(false);
                        setImagePickerTarget(null);
                      };
                      reader.readAsDataURL(file);
                    }
                  };
                  input.click();
                }}
                className="w-full py-2 bg-slate-100 hover:bg-slate-200 text-slate-700 rounded text-sm font-semibold"
              >本地上传</button>
              <button
                onClick={() => {
                  if (currentUser?.signature) {
                    fillPlaceholderSrc(imagePickerTarget, currentUser.signature);
                  }
                  setImagePickerOpen(false);
                  setImagePickerTarget(null);
                }}
                disabled={!currentUser?.signature}
                className={`w-full py-2 rounded text-sm font-semibold ${currentUser?.signature ? 'bg-slate-100 hover:bg-slate-200 text-slate-700' : 'bg-slate-50 text-slate-400 cursor-not-allowed'}`}
              >我的签名 {!currentUser?.signature && '(未上传)'}</button>
              <div>
                <div className="text-xs text-slate-500 mb-2">系统素材</div>
                <div className="flex flex-wrap gap-2 max-h-32 overflow-y-auto">
                  {imageAssets.map(asset => (
                    <button
                      key={asset.id}
                      onClick={() => { fillPlaceholderSrc(imagePickerTarget, asset.dataUrl); setImagePickerOpen(false); setImagePickerTarget(null); }}
                      className="w-16 h-16 border rounded overflow-hidden hover:ring-2 ring-accent"
                    >
                      <img src={asset.dataUrl} alt={asset.name} className="w-full h-full object-cover" />
                    </button>
                  ))}
                  {imageAssets.length === 0 && <div className="text-xs text-slate-400">暂无素材</div>}
                </div>
              </div>
            </div>
            <div className="mt-5 flex justify-end">
              <button onClick={() => { setImagePickerOpen(false); setImagePickerTarget(null); }} className="px-4 py-2 bg-slate-100 text-slate-600 rounded text-sm">取消</button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
