//! Iris Runtime Orchestrator
//!
//! 负责将 iris-sfc、iris-js、iris-dom、iris-layout 和 iris-gpu 连接在一起，
//! 形成完整的 Vue 3 运行时。
//!
//! # 架构流程
//!
//! ```text
//! 1. 初始化阶段
//!    → iris-js::init()
//!    → iris-dom::init()
//!
//! 2. 编译阶段
//!    iris-sfc::compile("App.vue")
//!    → 输出 JS 代码 + 样式
//!
//! 3. 执行阶段
//!    iris-js::eval(js_code)
//!    → Vue 创建组件实例
//!    → 生成虚拟 DOM
//!
//! 4. 渲染循环
//!    loop {
//!      处理事件 (iris-dom)
//!      更新虚拟 DOM (iris-js)
//!      GPU 渲染 (iris-gpu)
//!    }
//! ```
//!
//! # Z-Index 分层规范
//!
//! 渲染层叠顺序（从底层到顶层）：
//! - 背景层: z_index + 0 (GradientRect, Rect, RoundedRect)
//! - 边框层: z_index + 1 (Border)
//! - 文字层: z_index + 2 (Text, text-decoration)
//! - 图标层: z_index + 3 (Image, Icon)
//! - 悬浮层: z_index + 10 (tooltip, popup, modal overlay)

// HTML 渲染模式必需的依赖
use iris_layout::dom::DOMNode;
use iris_layout::vdom::VTree;
use iris_layout::layout::{compute_layout, measure_text};
use iris_layout::set_text_measurer;
use iris_layout::positioning::{PositionConfig, PositionType, compute_absolute_position};
use iris_layout::css::Stylesheet;
use iris_gpu::DrawCommand;
use iris_gpu::Renderer;

// Vue 模式可选的依赖
#[cfg(feature = "vue-sfc")]
use iris_dom::vnode::VNode;
#[cfg(feature = "vue-sfc")]
use iris_dom::event::{EventDispatcher, Event, EventType, EventData, EventListener, MouseEventData};

#[cfg(feature = "vue-sfc")]
use iris_js::{
    es_modules::EsModules,
    vue::{setup_complete_vue_environment, inject_render_helpers, execute_sfc_reactive_render,
        check_reactive_dirty, clear_reactive_dirty},
    vm::JsRuntime,
};

#[cfg(feature = "vue-sfc")]
use iris_sfc::SfcModule;

use std::collections::{HashMap, HashSet};
use std::path::Path;
use std::time::Instant;
use std::path::PathBuf;
use std::sync::mpsc::{channel, Receiver};

/// 字符 advance 宽度比例表（相对于 font_size）。
///
/// 正确做法是由字形的 `advance_width` 直接给出，这里是在尚未统一
/// 将 `SwashFont`/`FontAtlas` 接入 layout 回调前的过渡实现，目标是比原来的
/// `ASCII 0.6 / 非ASCII 1.0` 更接近真实测量值，避免图文混排时的切行错误。
///
/// 参考常见无衬线字体（Segoe UI / PingFang / Noto Sans）的统计 advance：
/// - 极窄 ASCII（i/l/j/I/!/./|/’等）≈ 0.28
/// - 窄 ASCII（t/f/r/1） ≈ 0.40
/// - 普通 ASCII 字母/数字 ≈ 0.55
/// - 宽 ASCII（W/M/m/w） ≈ 0.85
/// - 全角 CJK / 假名 / 谚文 ≈ 1.0
/// - 标点、空格 ≈ 0.25~0.45
pub(crate) fn char_advance_ratio(c: char) -> f32 {
    match c {
        // 全角空白
        '\u{3000}' => 1.0,
        // ASCII 空格与常见极窄字符
        ' ' | '\t' => 0.28,
        'i' | 'l' | 'j' | 'I' | '|' | '!' | '.' | ',' | ';' | ':' | '\'' | '`' => 0.28,
        // 窄 ASCII
        't' | 'f' | 'r' | '1' | '(' | ')' | '[' | ']' | '{' | '}' => 0.40,
        // 宽 ASCII
        'W' | 'M' | 'm' | 'w' | '@' | '%' => 0.90,
        _ => {
            let cp = c as u32;
            // ASCII 中的普通字母数字类似于 0.55em
            if c.is_ascii() {
                return 0.55;
            }
            // CJK 统一表意 / 扩展 A / 兆容 / 假名 / 谚文音节 / 全角及半角
            if (0x4E00..=0x9FFF).contains(&cp)
                || (0x3400..=0x4DBF).contains(&cp)
                || (0xF900..=0xFAFF).contains(&cp)
                || (0x3040..=0x309F).contains(&cp)
                || (0x30A0..=0x30FF).contains(&cp)
                || (0xAC00..=0xD7AF).contains(&cp)
                || (0xFF00..=0xFFEF).contains(&cp)
            {
                return 1.0;
            }
            // 组合记号、零宽连接符等不占宽度
            if (0x0300..=0x036F).contains(&cp) || cp == 0x200D || cp == 0xFE0F {
                return 0.0;
            }
            // 其他各国文字保守回退到 0.8em（拉丁/希腊/西里尔 等）
            0.8
        }
    }
}

use notify::{RecommendedWatcher, RecursiveMode, Watcher, Event as NotifyEvent};
use tokio::runtime::Runtime as TokioRuntime;
use tracing::{debug, info, warn};

use crate::animation_engine::{
    ElementAnimationState, KeyframeAnimation, TransitionConfig,
};
use crate::animation_engine::keyframes::FillMode;
use crate::dev_tools::DevTools;
use crate::dirty_rect_manager::{DirtyRectManager, DirtyRectStats};
use crate::error_handling::{ErrorBoundary, IrisError, ErrorSource, ErrorSeverity};

// 导入 hit_test 模块的类型
use super::hit_test::{HitIndex, HitArea, HitIndexStats};
#[cfg(feature = "vue-sfc")]
use super::events::EventListenerOptions;

/// 运行时编排器
///
/// 管理整个 Iris 运行时的生命周期，协调各模块的初始化和交互。
pub struct RuntimeOrchestrator {
    // Vue 模式特有字段
    #[cfg(feature = "vue-sfc")]
    /// JavaScript 运行时
    pub(crate) js_runtime: JsRuntime,
    
    #[cfg(feature = "vue-sfc")]
    /// ES 模块管理器（处理 import/export 转换）
    es_modules: EsModules,
    
    #[cfg(feature = "vue-sfc")]
    /// 当前根虚拟 DOM 节点（旧版）
    root_vnode: Option<VNode>,
    
    #[cfg(feature = "vue-sfc")]
    /// 组件注册表（下载和缓存开源组件源码）
    component_registry: Option<crate::orchestrator::ComponentRegistry>,
    
    // HTML 和 Vue 模式共用字段
    /// 当前虚拟 DOM 树（新版，从 SFC render 函数生成）
    vtree: Option<VTree>,
    /// 上一次的虚拟 DOM 树（用于 diff 计算）
    old_vtree: Option<VTree>,
    /// 当前 DOM 树（从 VTree 转换而来）
    pub(crate) dom_tree: Option<DOMNode>,
    /// CSS 样式表管理器（直接存储解析后的样式表）
    css_stylesheets: HashMap<String, Stylesheet>,
    
    // Vue 模式特有字段
    #[cfg(feature = "vue-sfc")]
    /// 事件分发器
    event_dispatcher: EventDispatcher,
    
    // HTML 和 Vue 模式共用字段
    /// GPU 渲染器（可选）
    gpu_renderer: Option<Renderer>,
    /// 视口宽度
    viewport_width: f32,
    /// 视口高度
    viewport_height: f32,
    /// 是否已初始化
    initialized: bool,
    /// 渲染相关
    /// 目标帧率（FPS）
    target_fps: u32,
    /// 上一帧的时间戳
    last_frame_time: Option<Instant>,
    /// 当前帧率
    current_fps: f64,
    /// 文件监听器（热重载）
    file_watcher: Option<RecommendedWatcher>,
    /// 文件事件接收器
    file_event_receiver: Option<Receiver<notify::Result<NotifyEvent>>>,
    /// 监听的 Vue 文件列表
    watched_files: Vec<PathBuf>,
    /// Tokio 运行时（用于异步任务）
    tokio_runtime: Option<TokioRuntime>,
    /// 最后热重载时间（用于防抖）
    last_hot_reload: Option<Instant>,
    /// 热重载防抖延迟（毫秒）
    hot_reload_debounce_ms: u64,
    /// 是否在渲染帧开始时自动处理 HMR 文件事件
    auto_hmr: bool,
    /// HMR 项目根目录（用于 hot_reload）
    hmr_project_root: Option<PathBuf>,
    /// DevTools 调试工具
    dev_tools: DevTools,
    /// ErrorBoundary 错误边界
    error_boundary: ErrorBoundary,
    /// 动画引擎 - 元素动画状态表（key: element_id）
    element_animations: HashMap<u64, ElementAnimationState>,
    /// 动画引擎 - 关键帧动画实例列表
    keyframe_animations: Vec<KeyframeAnimation>,
    /// 动画引擎 - 时间基准（用于计算动画绝对时间戳）
    animation_start_time: std::time::Instant,
    /// 动画引擎 - 上次动画更新时间
    last_animation_update: std::time::Instant,
    /// 动画引擎 - 计算出的动画值缓存（用于渲染命令生成时读取）
    animated_values_cache: HashMap<u64, HashMap<String, f32>>,
    /// 脏矩形管理器（性能优化 - 只重绘变化区域）
    dirty_rect_manager: DirtyRectManager,
    
    // Vue 模式特有字段
    #[cfg(feature = "vue-sfc")]
    /// 待处理事件队列（在 render_frame 中统一处理）
    pending_events: Vec<Event>,
    
    #[cfg(feature = "vue-sfc")]
    /// 当前拥有焦点的 DOM 节点 ID
    pub(crate) focused_node_id: Option<u64>,
    /// 不可见元素报告（用于在控制台输出元素不可见的原因）
    invisible_reports: std::cell::RefCell<Vec<String>>,
    /// 布局是否需要重新计算（视口尺寸变化时设置）
    layout_dirty: bool,
    /// HitTest 索引（用于事件分发和交互）
    pub(crate) hit_index: HitIndex,
    /// DrawCommand 索引 → DOMNode ID 映射（短期方案：维护元数据映射）
    #[cfg(feature = "vue-sfc")]
    pub(crate) command_to_node_map: std::collections::HashMap<usize, u64>,
    /// DOMNode ID → vnode_id 映射（用于事件系统）
    #[cfg(feature = "vue-sfc")]
    pub(crate) node_to_vnode_map: std::collections::HashMap<u64, String>,
    /// 脏标志（用于标记是否需要重渲染）
    pub(crate) dirty: bool,
    /// 事件委托规则（父节点 ID → [(选择器, 事件类型)]）
    #[cfg(feature = "vue-sfc")]
    pub(crate) event_delegations: HashMap<u64, Vec<(String, String)>>,
/// 可聚焦元素集合 (tabindex >= 0 的元素)
    #[cfg(feature = "vue-sfc")]
    #[allow(dead_code)]
    focusable_elements: std::collections::HashSet<u64>,

    // ============================================
    // 性能优化缓存
    // ============================================

    /// 事件处理器缓存 (vnode_id -> event_type -> 是否存在)
    #[cfg(feature = "vue-sfc")]
    pub(crate) event_handler_cache: std::collections::HashMap<String, std::collections::HashMap<String, bool>>,

    /// HitTest 结果缓存 (node_id -> HitArea)
    #[cfg(feature = "vue-sfc")]
    pub(crate) hit_test_cache: std::collections::HashMap<u64, Option<super::hit_test::HitArea>>,

    /// 缓存命中率统计
    #[cfg(feature = "vue-sfc")]
    pub(crate) cache_hit_count: u64,

    /// 缓存总请求数
    #[cfg(feature = "vue-sfc")]
    pub(crate) cache_total_count: u64,

    // ============================================
    // 高级事件功能
    // ============================================

    /// 事件监听器选项 (vnode_id -> event_type -> options)
    #[cfg(feature = "vue-sfc")]
    pub(crate) event_listener_options: std::collections::HashMap<String, std::collections::HashMap<String, EventListenerOptions>>,

    /// 双击检测状态 (node_id -> last_click_time)
    #[cfg(feature = "vue-sfc")]
    pub(crate) last_click_times: std::collections::HashMap<u64, std::time::Instant>,
}

impl RuntimeOrchestrator {
    /// 创建新的运行时编排器
    pub fn new() -> Self {
        Self {
            // Vue 模式特有字段
            #[cfg(feature = "vue-sfc")]
            js_runtime: JsRuntime::new(),
            
            #[cfg(feature = "vue-sfc")]
            es_modules: EsModules::new(),
            
            #[cfg(feature = "vue-sfc")]
            root_vnode: None,
            
            #[cfg(feature = "vue-sfc")]
            component_registry: None,
            
            // HTML 和 Vue 模式共用字段
            vtree: None,
            old_vtree: None,
            dom_tree: None,
            css_stylesheets: HashMap::new(),
            
            #[cfg(feature = "vue-sfc")]
            event_dispatcher: EventDispatcher::new(),
            
            gpu_renderer: None,
            viewport_width: 800.0,
            viewport_height: 600.0,
            initialized: false,
            target_fps: 60,
            last_frame_time: None,
            current_fps: 0.0,
            dirty: true,
            // 文件监听器相关
            file_watcher: None,
            file_event_receiver: None,
            watched_files: Vec::new(),
            tokio_runtime: None,
            last_hot_reload: None,
            hot_reload_debounce_ms: 500, // 默认 500ms 防抖
            auto_hmr: false,
            hmr_project_root: None,
            dev_tools: DevTools::new(),
            error_boundary: ErrorBoundary::new("RuntimeOrchestrator"),
            // 动画引擎
            element_animations: HashMap::new(),
            keyframe_animations: Vec::new(),
            animation_start_time: Instant::now(),
            last_animation_update: Instant::now(),
            animated_values_cache: HashMap::new(),
            // 脏矩形管理器（使用默认视口尺寸 800x600）
            dirty_rect_manager: DirtyRectManager::new(800.0, 600.0),
            
            // Vue 模式特有字段
            #[cfg(feature = "vue-sfc")]
            pending_events: Vec::new(),
            
            #[cfg(feature = "vue-sfc")]
            focused_node_id: None,
            // 不可见元素报告
            invisible_reports: std::cell::RefCell::new(Vec::new()),
            // 布局脏标志（视口尺寸变化时需重排）
            layout_dirty: true,
            // HitTest 索引（用于事件分发）
            hit_index: HitIndex::new(),
            // DrawCommand → DOMNode 映射（数据流完整性）
            #[cfg(feature = "vue-sfc")]
            command_to_node_map: std::collections::HashMap::new(),
            // DOMNode ID → vnode_id 映射（数据流完整性）
            #[cfg(feature = "vue-sfc")]
            node_to_vnode_map: std::collections::HashMap::new(),
            // 事件委托（初始为空）
            #[cfg(feature = "vue-sfc")]
            event_delegations: HashMap::new(),
            // 可聚焦元素集合（初始为空）
            #[cfg(feature = "vue-sfc")]
            focusable_elements: std::collections::HashSet::new(),

// 性能优化缓存
            #[cfg(feature = "vue-sfc")]
            event_handler_cache: std::collections::HashMap::new(),
            #[cfg(feature = "vue-sfc")]
            hit_test_cache: std::collections::HashMap::new(),
            #[cfg(feature = "vue-sfc")]
            cache_hit_count: 0,
            #[cfg(feature = "vue-sfc")]
            cache_total_count: 0,

            // 高级事件功能
            #[cfg(feature = "vue-sfc")]
            event_listener_options: std::collections::HashMap::new(),
            #[cfg(feature = "vue-sfc")]
            last_click_times: std::collections::HashMap::new(),
        }
    }

    /// 初始化运行时环境
    ///
    /// 按照正确的顺序初始化所有子模块。
    #[cfg(feature = "vue-sfc")]
    pub fn initialize(&mut self) -> Result<(), String> {
        info!("Initializing Iris runtime...");

        // 1. 初始化 JavaScript 运行时并注入 Vue
        debug!("Initializing JS runtime with Vue...");
        if let Err(e) = setup_complete_vue_environment(&mut self.js_runtime) {
            let msg = format!("Failed to setup Vue environment: {}", e);
            self.report_error(&msg, ErrorSource::Script, ErrorSeverity::Fatal);
            return Err(msg);
        }

        // 2. 注入 BOM API
        debug!("Injecting BOM API...");
        if let Err(e) = self.js_runtime.inject_bom(1280, 720) {
            let msg = format!("Failed to inject BOM: {}", e);
            self.report_error(&msg, ErrorSource::Script, ErrorSeverity::Fatal);
            return Err(msg);
        }

        self.initialized = true;
        
        // 3. 注入 ES Modules 支持
        debug!("Injecting ES Modules system...");
        self.es_modules
            .inject(self.js_runtime.context_mut())
            .map_err(|e| format!("Failed to inject ES Modules: {}", e))?;

        // 4. 注册组件到 DevTools
        self.dev_tools.register_component("RuntimeOrchestrator", "/");
        
        info!("Iris runtime initialized successfully");
        Ok(())
    }

    /// 初始化组件注册表（下载开源组件源码）
    #[cfg(feature = "vue-sfc")]
    pub fn initialize_component_registry(&mut self, registry_path: Option<&str>) -> Result<(), String> {
        info!("Initializing component registry...");
        
        // 缓存目录：~/.iris/component-cache
        let cache_dir = dirs::home_dir()
            .ok_or("Cannot find home directory")?
            .join(".iris")
            .join("component-cache");
        
        let mut registry = crate::orchestrator::ComponentRegistry::new(cache_dir)?;
        
        // 加载注册表文件
        let registry_path = registry_path.unwrap_or("docs/vue-components-registry.json");
        if std::path::Path::new(registry_path).exists() {
            registry.load_from_file(registry_path)?;
            info!(path = registry_path, "Component registry loaded");
        } else {
            warn!(path = registry_path, "Component registry file not found, using inference only");
        }
        
        self.component_registry = Some(registry);
        Ok(())
    }

    /// 编译并加载 Vue SFC 组件
    ///
    /// 将 .vue 文件编译为 JavaScript，然后在 JS 运行时中执行。
    #[cfg(feature = "vue-sfc")]
    pub fn load_vue_app<P: AsRef<Path>>(&mut self, path: P) -> Result<(), String> {
        if !self.initialized {
            return Err("Runtime not initialized. Call initialize() first.".to_string());
        }

        let path = path.as_ref();
        info!(path = ?path, "Loading Vue application...");

        // 1. 编译 SFC
        let sfc_module = match self.compile_sfc(path) {
            Ok(m) => m,
            Err(e) => {
                let msg = format!("Failed to compile SFC: {}", e);
                self.report_error(&msg, ErrorSource::Script, ErrorSeverity::Error);
                return Err(msg);
            }
        };
        info!(name = %sfc_module.name, "SFC compiled successfully");

        // 2. 预加载子组件依赖（收集子组件 CSS 并注入 CSSOM）
        let parent_dir = path.parent()
            .filter(|p| !p.as_os_str().is_empty())
            .unwrap_or_else(|| Path::new("."));
        let child_css = self.preload_sfc_dependencies(&sfc_module, parent_dir);

        // 2b. 将主组件样式与子组件样式合并注入 CSSOM
        let main_css: String = sfc_module.styles.iter()
            .map(|s| s.css.as_str())
            .collect::<Vec<_>>()
            .join("\n");
        let combined_css = if child_css.is_empty() {
            main_css.clone()
        } else if main_css.is_empty() {
            child_css
        } else {
            format!("{}\n{}", main_css, child_css)
        };
        if !combined_css.is_empty() {
            info!(css_len = combined_css.len(), "Adding stylesheet from SFC + child components...");
            self.add_css_stylesheet("main", &combined_css);
        }

        // 3. 在 JS 运行时中执行
        if let Err(e) = self.execute_sfc_module(&sfc_module, &sfc_module.name) {
            let msg = format!("Failed to execute SFC module: {}", e);
            self.report_error(&msg, ErrorSource::Script, ErrorSeverity::Error);
            return Err(msg);
        }
        info!("SFC module executed");

        // 3. 创建虚拟 DOM（简化版）
        self.root_vnode = Some(VNode::element("div"));
        info!("Virtual DOM created");

        Ok(())
    }

    /// 编译 SFC 模块
    #[cfg(feature = "vue-sfc")]
    fn compile_sfc(&self, path: &Path) -> Result<SfcModule, String> {
        iris_sfc::compile(path).map_err(|e| {
            format!("Failed to compile SFC {}: {}", path.display(), e)
        })
    }

    /// 在 JS 运行时中执行 SFC 模块
    ///
    /// 使用 EsModules 转换 import/export 语句，
    /// 然后执行转换后的代码。
    ///
    /// # 参数
    ///
    /// * `sfc_module` - SFC 模块
    /// * `specifier` - 模块标识符（用于 ESM 模块注册，如 "./MockTableDemo.vue"）
    #[cfg(feature = "vue-sfc")]
    pub fn execute_sfc_module(&mut self, sfc_module: &SfcModule, specifier: &str) -> Result<(), String> {
        // 1. 注入样式
        for (index, style_block) in sfc_module.styles.iter().enumerate() {
            debug!(style_index = index, scoped = style_block.scoped, "Injecting style...");
        }

        // 2. 使用 EsModules 转换脚本（处理 import/export）
        let transformed = self.es_modules.transform_module(
            specifier,
            &sfc_module.script
        );
        
        debug!(script_len = transformed.len(), "Executing SFC script (ESM transformed)...");

        // 3. 执行转换后的代码
        self.js_runtime.eval(&transformed).map_err(|e| {
            format!("Failed to execute SFC script: {}", e)
        })?;

        Ok(())
    }

    /// 预加载 SFC 模块的 .vue 子组件依赖
    ///
    /// 解析 SFC 脚本中的 import 语句，找到所有 .vue 文件导入，
    /// 编译并注册到 ESM 模块系统中，使 __getModule 可以正确解析。
    ///
    /// # 参数
    ///
    /// * `sfc_module` - 已编译的 SFC 模块
    /// * `parent_dir` - 入口文件所在目录（用于解析相对路径）
    #[cfg(feature = "vue-sfc")]
    pub fn preload_sfc_dependencies(&mut self, sfc_module: &SfcModule, parent_dir: &Path) -> String {
        let mut child_css = String::new();
        let imports = self.es_modules.parse_imports(&sfc_module.script);
        info!("Preload: found {} imports in script", imports.len());
        for import_specifier in &imports {
            info!("Preload: checking import '{}'", import_specifier);
            // 仅处理相对路径的 .vue 文件导入（跳过 "vue" 包和 node_modules）
            if import_specifier.ends_with(".vue") && import_specifier.starts_with(".") {
                let resolved = parent_dir.join(import_specifier);
                info!("Preload: resolved to {}", resolved.display());
                if resolved.exists() {
                    info!("Pre-loading sub-component: {} -> {}", import_specifier, resolved.display());
                    match self.compile_sfc(&resolved) {
                        Ok(sub_module) => {
                            // 收集子组件的 CSS
                            let sub_css: String = sub_module.styles.iter()
                                .map(|s| s.css.as_str())
                                .collect::<Vec<_>>()
                                .join("\n");
                            if !sub_css.is_empty() {
                                child_css.push_str("\n");
                                child_css.push_str(&sub_css);
                            }
                            
                            // 使用原始 import specifier 注册到 ESM 模块系统
                            if let Err(e) = self.execute_sfc_module(&sub_module, import_specifier) {
                                info!("Failed to pre-load sub-component {}: {}", import_specifier, e);
                            } else if let Some(comp_name) = resolved.file_stem().and_then(|s| s.to_str()) {
                                info!("Registering component '{}' in ComponentRegistry", comp_name);

                                // 步骤1: 评估扁平化的 render 函数（创建全局 render 函数）
                                // render 函数已被扁平化生成（无深度嵌套），Boa 可安全解析
                                if let Err(e) = self.js_runtime.eval(&sub_module.render_fn) {
                                    warn!("Failed to eval render fn for '{}': {}", comp_name, e);
                                }

                                // 步骤2: 从 ESM 模块获取组件定义，设置 render 并注册到 ComponentRegistry
                                let register_js = format!(
                                    r#"
(function() {{
  var __mod = __getModule("{specifier}");
  if (__mod && __mod["default"]) {{
    if (typeof render === 'function') {{
      __mod["default"].render = render;
    }}
    ComponentRegistry.register("{name}", __mod["default"]);
  }}
}})();
"#,
                                    specifier = import_specifier,
                                    name = comp_name
                                );
                                if let Err(e) = self.js_runtime.eval(&register_js) {
                                    warn!("Failed to register component '{}': {}", comp_name, e);
                                }
                            }
                        }
                        Err(e) => {
                            warn!("Failed to compile sub-component {}: {}", import_specifier, e);
                        }
                    }
                } else {
                    warn!("Sub-component not found (skipped): {} -> {}", import_specifier, resolved.display());
                }
            }
        }
        child_css
    }

    /// 获取当前虚拟 DOM
    #[cfg(feature = "vue-sfc")]
    pub fn root_vnode(&self) -> Option<&VNode> {
        self.root_vnode.as_ref()
    }

    /// 获取 JS 运行时的可变引用
    #[cfg(feature = "vue-sfc")]
    pub fn js_runtime(&mut self) -> &mut JsRuntime {
        &mut self.js_runtime
    }

    /// 获取当前的虚拟 DOM 树
    pub fn vtree(&self) -> Option<&VTree> {
        self.vtree.as_ref()
    }

    /// 从响应式渲染循环中获取更新后的 VTree
    ///
    /// 在响应式数据（ref/reactive）变化后调用，
    /// 读取 watchEffect 重新渲染后的 __vnode_map 并重建 VTree。
    ///
    /// 与旧版本相比，此版本会计算新旧 VTree 的 diff patches 并增量更新 DOM 树，
    /// 避免全量重建。
    #[cfg(feature = "vue-sfc")]
    pub fn update_vtree_from_reactive(&mut self) -> Result<(), String> {
        let new_vtree = iris_js::vue::get_vtree_from_runtime(&mut self.js_runtime)?;

        // 如果有 DOM 树和当前 VTree，计算 diff 并增量更新 DOM
        if let Some(ref mut dom_tree) = self.dom_tree.as_mut() {
            if let Some(current_vtree) = self.vtree.as_ref() {
                let patches = new_vtree.diff(current_vtree);
                if !patches.is_empty() {
                    debug!(patch_count = patches.len(), "Applying reactive diff patches");
                    new_vtree.apply_patches(dom_tree, &patches);
                }
            }
        }

        // 保存旧 VTree 引用，更新当前 VTree
        self.old_vtree = self.vtree.take();
        self.vtree = Some(new_vtree);

        Ok(())
    }

    /// 编译并执行 SFC，生成完整的 VTree
    ///
    /// 这是 Phase B 的核心功能：将 SFC 编译结果转换为虚拟 DOM 树
    ///
    /// # 流程
    ///
    /// 1. 编译 SFC 文件
    /// 2. 注入 render 辅助函数
    /// 3. 执行 SFC 脚本
    /// 4. 注册组件到 ComponentRegistry
    /// 5. 执行 render 函数生成 VTree
    /// 6. 存储 VTree 供后续使用
    ///
    /// # 示例
    ///
    /// ```ignore
    /// let mut orchestrator = RuntimeOrchestrator::new();
    /// orchestrator.initialize()?;
    /// orchestrator.load_sfc_with_vtree("App.vue")?;
    /// 
    /// if let Some(vtree) = orchestrator.vtree() {
    ///     // 使用 VTree 进行渲染
    /// }
    /// ```
    #[cfg(feature = "vue-sfc")]
    pub fn load_sfc_with_vtree<P: AsRef<Path>>(&mut self, path: P) -> Result<(), String> {
        if !self.initialized {
            return Err("Runtime not initialized. Call initialize() first.".to_string());
        }

        // 每次重新加载 SFC 时完全重置字体图集（清空像素数据，保证干净启动）
        if let Some(renderer) = self.gpu_renderer.as_mut() {
            if let Some(atlas) = renderer.font_atlas_mut() {
                atlas.clear();
                info!("Font atlas fully cleared for clean reload");
            }
            // 立即强制上传空白纹理到 GPU，覆盖旧数据
            renderer.force_sync_font_atlas();
            info!("Font atlas GPU texture synchronized (blank)");
        }

        let path = path.as_ref();
        info!(path = ?path, "Loading SFC with VTree generation...");

        // 1. 编译 SFC
        let sfc_module = match self.compile_sfc(path) {
            Ok(m) => m,
            Err(e) => {
                let msg = format!("Failed to compile SFC: {}", e);
                self.report_error(&msg, ErrorSource::Script, ErrorSeverity::Error);
                return Err(msg);
            }
        };
        info!(name = %sfc_module.name, "SFC compiled successfully");

        // 2b. 预加载子组件依赖（在入口 SFC 执行前编译并注册 .vue 导入）
        //     同时收集子组件的 CSS
        let parent_dir = path.parent()
            .filter(|p| !p.as_os_str().is_empty())
            .unwrap_or_else(|| Path::new("."));
        let child_css = self.preload_sfc_dependencies(&sfc_module, parent_dir);

        // 2c. 将 SFC 样式（主组件 + 子组件）注入 CSSOM 管理器
        let main_css: String = sfc_module.styles.iter()
            .map(|s| s.css.as_str())
            .collect::<Vec<_>>()
            .join("\n");
        let combined_css = if child_css.is_empty() {
            main_css.clone()
        } else if main_css.is_empty() {
            child_css
        } else {
            format!("{}\n{}", main_css, child_css)
        };
        if !combined_css.is_empty() {
            info!(css_len = combined_css.len(), "Adding stylesheet from SFC styles (main + components)...");
            self.add_css_stylesheet("main", &combined_css);
        } else {
            debug!("No styles found in SFC, adding empty stylesheet");
            self.css_stylesheets.insert("main".to_string(), Stylesheet::new());
        }

        // 2. 注入 render 辅助函数
        debug!("Injecting render helpers...");
        if let Err(e) = inject_render_helpers(&mut self.js_runtime) {
            let msg = format!("Failed to inject render helpers: {}", e);
            self.report_error(&msg, ErrorSource::Script, ErrorSeverity::Error);
            return Err(msg);
        }

        // 3. 执行 SFC 脚本（初始化组件）
        if let Err(e) = self.execute_sfc_module(&sfc_module, &sfc_module.name) {
            let msg = format!("Failed to execute SFC script: {}", e);
            self.report_error(&msg, ErrorSource::Script, ErrorSeverity::Error);
            return Err(msg);
        }
        info!("SFC script executed");

        // 4. 注册组件到 ComponentRegistry
        let component_name = path.file_stem()
            .and_then(|s| s.to_str())
            .unwrap_or("unknown");
        debug!(name = component_name, "Registering component...");
        let register_js = format!(
            r#"
(function() {{
  var __mod = __getModule("{module}");
  if (__mod && __mod["default"]) {{
    ComponentRegistry.register("{name}", __mod["default"]);
  }}
}})();
"#,
            module = sfc_module.name,
            name = component_name
        );
        if let Err(e) = self.js_runtime.eval(&register_js) {
            let msg = format!("Failed to register component: {}", e);
            self.report_error(&msg, ErrorSource::Script, ErrorSeverity::Warning);
            // 组件注册失败不阻止后续流程
        }
        info!("Component registered: {}", component_name);

        // 5. 生成 VTree（通过实际执行 render 函数）
        debug!("Generating VTree by executing render function...");
        
        let vtree = match execute_sfc_reactive_render(
            &mut self.js_runtime,
            &sfc_module.render_fn,
            &sfc_module.name,
        ) {
            Ok(v) => v,
            Err(e) => {
                let msg = format!("Failed to execute render function: {}", e);
                self.report_error(&msg, ErrorSource::Render, ErrorSeverity::Error);
                return Err(msg);
            }
        };
        info!("VTree generated successfully from render function");
        
        // 6. 存储旧 VTree，然后存储新 VTree
        self.old_vtree = self.vtree.take();
        self.vtree = Some(vtree);
        
        // 7. 注册组件到 DevTools
        let name = path.file_stem()
            .and_then(|s| s.to_str())
            .unwrap_or("unknown");
        self.dev_tools.register_component(name, &path.to_string_lossy());
        
        info!("SFC loaded successfully with VTree");

        Ok(())
    }

    /// 加载 Vue SFC 文件（直接解析，不执行 JS）
    /// 
    /// 这是当前的主要加载方式：
    /// 1. 从 .vue 文件提取 <style> CSS
    /// 2. 从 .vue 文件的 <template> 构建 VTree
    /// 3. 不执行任何 JavaScript（避免浏览器 API 依赖）
    /// 
    /// # 参数
    /// 
    /// * `vue_path` - .vue 文件路径（两个参数相同）
    /// * `_unused_js_path` - 保留用于未来兼容（目前不使用）
    #[cfg(feature = "vue-sfc")]
    pub fn load_compiled_js<P: AsRef<Path>, Q: AsRef<Path>>(
        &mut self,
        _unused_js_path: P,  // 保留参数名以兼容旧代码
        vue_path: Q,
    ) -> Result<(), String> {
        if !self.initialized {
            return Err("Runtime not initialized. Call initialize() first.".to_string());
        }

        let vue_path = vue_path.as_ref();
        
        info!(vue_path = ?vue_path, "Loading Vue SFC with component imports...");

        // 1. 读取 .vue 文件
        let vue_source = std::fs::read_to_string(vue_path)
            .map_err(|e| format!("Failed to read Vue source file: {}", e))?;
        
        // 2. 从 Vue 源文件提取 <style> 内容
        let css = Self::extract_vue_styles(&vue_source);
        if !css.is_empty() {
            info!(css_len = css.len(), "Adding stylesheet from Vue source...");
            self.add_css_stylesheet("main", &css);
        } else {
            debug!("No styles found in Vue source, adding empty stylesheet");
            self.css_stylesheets.insert("main".to_string(), Stylesheet::new());
        }

        // 3. 执行 <script setup> 获取变量值（使用 Boa）
        debug!("Executing script setup with Boa...");
        let js_variables = self.execute_script_setup(&vue_source)?;
        info!(variables = ?js_variables.keys().collect::<Vec<_>>(), "Script setup executed");

        // 4. 解析 import 语句，获取子组件路径
        let component_imports = self.parse_component_imports(&vue_source, vue_path)?;
        info!(components = ?component_imports.keys().collect::<Vec<_>>(), "Component imports parsed");

        // 5. 递归加载子组件（返回 DOMNode）
        let mut component_doms = std::collections::HashMap::new();
        for (component_name, component_path) in &component_imports {
            debug!(component = component_name, path = ?component_path, "Loading component...");
            let component_dom = self.load_component_dom(component_path)?;
            component_doms.insert(component_name.clone(), component_dom);
        }
        info!("Component DOMs loaded");

        // 6. 从 Vue 源文件的 <template> 构建 VTree（替换变量 + 展开组件）
        debug!("Building VTree from Vue source template...");
        let vtree = self.build_vtree_from_vue_source(&vue_source, &js_variables, &component_doms)?;
        info!("VTree built from Vue source");

        // 7. 存储 VTree
        self.old_vtree = self.vtree.take();
        self.vtree = Some(vtree);

        // 8. 注册组件到 DevTools
        let name = vue_path.file_stem()
            .and_then(|s| s.to_str())
            .unwrap_or("unknown");
        self.dev_tools.register_component(name, &vue_path.to_string_lossy());

        info!("Vue SFC loaded successfully (CSS + JS execution + Components + VTree)");
        Ok(())
    }

    /// 从 Vue 源文件提取 <style> 内容
    #[cfg(feature = "vue-sfc")]
    fn extract_vue_styles(source: &str) -> String {
        use regex::Regex;
        
        let style_re = Regex::new(r#"(?s)<style[^>]*>(.*?)</\s*style\s*>"#)
            .expect("Invalid regex");
        
        let mut all_css = String::new();
        for cap in style_re.captures_iter(source) {
            if let Some(css) = cap.get(1) {
                if !all_css.is_empty() {
                    all_css.push('\n');
                }
                all_css.push_str(css.as_str());
            }
        }
        
        all_css
    }

    /// 执行 <script setup> 部分，获取变量值
    #[cfg(feature = "vue-sfc")]
    fn execute_script_setup(&mut self, source: &str) -> Result<std::collections::HashMap<String, String>, String> {
        use regex::Regex;
        use boa_engine::{Context, Source};
        
        // 提取 <script setup> 内容
        let script_re = Regex::new(r#"(?s)<script[^>]*setup[^>]*>(.*?)</\s*script\s*>"#)
            .expect("Invalid regex");
        
        let script_content = match script_re.captures(source) {
            Some(cap) => cap.get(1).map(|m| m.as_str()).unwrap_or(""),
            None => {
                debug!("No <script setup> found");
                return Ok(std::collections::HashMap::new());
            }
        };
        
        if script_content.trim().is_empty() {
            return Ok(std::collections::HashMap::new());
        }
        
        debug!(script_len = script_content.len(), "Found <script setup>");
        
        // 创建 Boa 上下文
        let mut context = Context::builder().build()
            .map_err(|e| format!("Failed to create JS context: {}", e))?;
        
        // 注入 Vue 响应式 API（简化版）
        context.eval(Source::from_bytes(r#"
            // ref 实现
            function ref(value) {
                return { value: value };
            }
            
            // reactive 实现
            function reactive(obj) {
                return obj;
            }
            
            // computed 实现
            function computed(fn) {
                return { value: fn() };
            }
            
            // 导入模拟
            function require(name) {
                if (name === 'vue') {
                    return { ref, reactive, computed };
                }
                return {};
            }
        "#)).map_err(|e| format!("Failed to inject Vue API: {}", e))?;
        
        // 执行 script setup
        context.eval(Source::from_bytes(script_content))
            .map_err(|e| format!("Failed to execute script setup: {}", e))?;
        
        // 提取变量（遍历全局对象）
        let mut variables = std::collections::HashMap::new();
        
        // 尝试获取常见变量
        let var_names = ["appTitle", "title", "count", "message"];
        
        for var_name in var_names {
            let js_code = format!(
                "typeof {0} !== 'undefined' ? String({0}.value !== undefined ? {0}.value : {0}) : null",
                var_name
            );
            
            if let Ok(value) = context.eval(Source::from_bytes(js_code.as_bytes())) {
                if let Ok(js_string) = value.to_string(&mut context) {
                    if let Ok(str_val) = js_string.to_std_string() {
                        if str_val != "null" && str_val != "undefined" {
                            variables.insert(var_name.to_string(), str_val.clone());
                            debug!(variable = var_name, value = &str_val, "Extracted variable");
                        }
                    }
                }
            }
        }
        
        Ok(variables)
    }

    /// 解析组件导入语句
    #[cfg(feature = "vue-sfc")]
    fn parse_component_imports(&self, source: &str, base_path: &std::path::Path) -> Result<std::collections::HashMap<String, std::path::PathBuf>, String> {
        use regex::Regex;
        
        // 匹配 import X from './X.vue'
        let import_re = Regex::new(r#"import\s+(\w+)\s+from\s+['\"]([^'\"]+\.vue)['\"]"#)
            .expect("Invalid regex");
        
        let mut components = std::collections::HashMap::new();
        
        for cap in import_re.captures_iter(source) {
            let component_name = cap.get(1).map(|m| m.as_str()).unwrap_or("");
            let relative_path = cap.get(2).map(|m| m.as_str()).unwrap_or("");
            
            if !component_name.is_empty() && !relative_path.is_empty() {
                // 解析相对路径
                let component_path = base_path.parent()
                    .ok_or("Failed to get parent directory")?
                    .join(relative_path);
                
                components.insert(component_name.to_string(), component_path);
                debug!(component = component_name, path = ?relative_path, "Found component import");
            }
        }
        
        Ok(components)
    }

    /// 加载子组件的 DOM 节点
    #[cfg(feature = "vue-sfc")]
    fn load_component_dom(&mut self, component_path: &std::path::Path) -> Result<iris_layout::dom::DOMNode, String> {
        debug!(path = ?component_path, "Loading component DOM...");
        
        // 尝试从组件名推断并下载源码
        let component_name = component_path.file_stem()
            .and_then(|s| s.to_str())
            .unwrap_or("Unknown");
        
        let source = if let Some(ref mut registry) = self.component_registry {
            // 尝试从注册表下载
            match registry.fetch_component_source(component_name) {
                Ok(source) => {
                    info!(component = component_name, "Loaded component from registry");
                    source
                }
                Err(e) => {
                    debug!(component = component_name, error = %e, "Registry fetch failed, fallback to local file");
                    // 回退到本地文件
                    std::fs::read_to_string(component_path)
                        .map_err(|e| format!("Failed to read component {}: {}", component_path.display(), e))?
                }
            }
        } else {
            // 没有注册表，直接读取本地文件
            std::fs::read_to_string(component_path)
                .map_err(|e| format!("Failed to read component {}: {}", component_path.display(), e))?
        };
        
        // 提取样式
        let css = Self::extract_vue_styles(&source);
        if !css.is_empty() {
            // 合并到主样式表
            // TODO: 处理 scoped CSS
        }
        
        // 执行 script setup
        let variables = self.execute_script_setup(&source)?;
        
        // 解析 template 为 DOMNode
        let mut dom = self.simple_parse_template(&source)?;
        
        // 替换变量
        self.replace_variables_in_dom(&mut dom, &variables);
        
        Ok(dom)
    }

    /// 从 Vue 源文件的 <template> 构建 VTree
    #[cfg(feature = "vue-sfc")]
    fn build_vtree_from_vue_source(
        &mut self,
        source: &str,
        variables: &std::collections::HashMap<String, String>,
        component_doms: &std::collections::HashMap<String, iris_layout::dom::DOMNode>,
    ) -> Result<VTree, String> {
        debug!("Building VTree from Vue source template...");
        
        // 简单解析：提取 template 内容并构建基本 DOM 树
        let mut dom_root = self.simple_parse_template(source)?;
        
        // 替换文本节点中的变量（{{ varName }}）
        self.replace_variables_in_dom(&mut dom_root, variables);
        
        // 展开组件标签（<ChildComponent /> -> 实际 DOM）
        self.expand_components_in_dom(&mut dom_root, component_doms)?;
        
        info!("DOM tree built from template");
        
        // 转换为 VTree
        Ok(VTree::from_dom_node(&dom_root))
    }

    /// 在 DOM 树中替换变量（{{ varName }} -> value）
    #[cfg(feature = "vue-sfc")]
    fn replace_variables_in_dom(&self, node: &mut iris_layout::dom::DOMNode, variables: &std::collections::HashMap<String, String>) {
        use regex::Regex;
        use iris_layout::dom::NodeType;
        
        // 如果是文本节点，替换变量
        if let NodeType::Text(ref mut text) = node.node_type {
            let var_re = Regex::new(r"\{\{\s*(.+?)\s*\}\}").expect("Invalid regex");
            
            let new_text = var_re.replace_all(text, |caps: &regex::Captures| {
                let expression = &caps[1];
                
                // 尝试在 Boa 中执行表达式
                if let Some(value) = self.evaluate_expression(expression, variables) {
                    value
                } else {
                    // 如果执行失败，保留原始表达式
                    format!("{{{{ {} }}}}", expression)
                }
            });
            
            if new_text.as_ref() != text.as_str() {
                debug!(old_text = text.as_str(), new_text = new_text.as_ref(), "Replaced variables");
                *text = new_text.to_string();
            }
        }
        
        // 递归处理子节点
        for child in &mut node.children {
            self.replace_variables_in_dom(child, variables);
        }
    }

    /// 展开组件标签为实际 DOM 节点
    #[cfg(feature = "vue-sfc")]
    fn expand_components_in_dom(
        &mut self,
        node: &mut iris_layout::dom::DOMNode,
        component_doms: &std::collections::HashMap<String, iris_layout::dom::DOMNode>,
    ) -> Result<(), String> {
        use iris_layout::dom::NodeType;
        
        // 如果当前节点是元素节点
        if let NodeType::Element(ref tag) = node.node_type {
            // 检查是否是已知组件
            if let Some(component_dom) = component_doms.get(tag) {
                debug!(component = tag, "Expanding component...");
                
                // 克隆组件的 DOM 节点
                let cloned_node = Self::clone_dom_node(component_dom);
                
                // 替换当前节点
                *node = cloned_node;
            }
        }
        
        // 递归处理子节点（需要收集索引避免借用冲突）
        let child_indices: Vec<usize> = (0..node.children.len()).collect();
        for idx in child_indices {
            self.expand_components_in_dom(&mut node.children[idx], component_doms)?;
        }
        
        Ok(())
    }

    /// 克隆 DOM 节点（深拷贝）
    #[cfg(feature = "vue-sfc")]
    fn clone_dom_node(node: &iris_layout::dom::DOMNode) -> iris_layout::dom::DOMNode {
        use iris_layout::dom::{DOMNode, NodeType};
        
        // 根据节点类型创建新节点
        let mut new_node = match &node.node_type {
            NodeType::Element(tag) => DOMNode::new_element(tag),
            NodeType::Text(text) => DOMNode::new_text(text),
            NodeType::Comment(comment) => {
                let mut n = DOMNode::new_element("!--");
                n.node_type = NodeType::Comment(comment.clone());
                n
            }
        };
        
        // 复制属性
        new_node.attributes = node.attributes.clone();
        
        // 递归克隆子节点
        new_node.children = node.children.iter().map(|c| Self::clone_dom_node(c)).collect();
        
        new_node
    }

    /// 在 Boa 中执行表达式
    #[cfg(feature = "vue-sfc")]
    fn evaluate_expression(&self, expression: &str, variables: &std::collections::HashMap<String, String>) -> Option<String> {
        use boa_engine::{Context, Source};
        
        // 创建 Boa 上下文
        let mut context = match Context::builder().build() {
            Ok(ctx) => ctx,
            Err(_) => return None,
        };
        
        // 注入变量
        for (name, value) in variables {
            let js_code = format!("var {} = {};", name, value);
            if context.eval(Source::from_bytes(js_code.as_bytes())).is_err() {
                // 尝试作为字符串注入
                let js_code = format!("var {} = {:?};", name, value);
                let _ = context.eval(Source::from_bytes(js_code.as_bytes()));
            }
        }
        
        // 执行表达式
        match context.eval(Source::from_bytes(expression.as_bytes())) {
            Ok(value) => {
                if let Ok(js_string) = value.to_string(&mut context) {
                    if let Ok(str_val) = js_string.to_std_string() {
                        if str_val != "undefined" && str_val != "null" {
                            debug!(expression = expression, result = &str_val, "Expression evaluated");
                            return Some(str_val);
                        }
                    }
                }
                None
            }
            Err(e) => {
                debug!(expression = expression, error = %e, "Failed to evaluate expression");
                None
            }
        }
    }

    /// 从 SFC 文件构建 VTree（避免 JavaScript 执行）
    #[allow(dead_code)]
    fn build_vtree_from_file<P: AsRef<Path>>(&self, path: P) -> Result<VTree, String> {
        debug!("Building VTree from SFC file...");
        
        // 读取文件
        let source = std::fs::read_to_string(path.as_ref())
            .map_err(|e| format!("Failed to read file: {}", e))?;
        
        // 简单解析：提取 template 内容并构建基本 DOM 树
        let dom_root = self.simple_parse_template(&source)?;
        
        info!("DOM tree built from template");
        
        // 转换为 VTree
        Ok(VTree::from_dom_node(&dom_root))
    }

    /// 完整模板解析（使用 html5ever）
    #[allow(dead_code)]
    fn simple_parse_template(&self, source: &str) -> Result<DOMNode, String> {
        use html5ever::tendril::{Tendril, TendrilSink};
        use html5ever::{local_name, namespace_url, ns, parse_fragment, ParseOpts, QualName};
        use markup5ever_rcdom::RcDom;
        
        // 提取 <template> 内容
        let template_re = regex::Regex::new(r#"(?s)<template[^>]*>(.*?)</\s*template\s*>"#)
            .map_err(|e| format!("Regex error: {}", e))?;
        
        let template_content = match template_re.captures(source) {
            Some(caps) => caps.get(1).map(|m| m.as_str()).unwrap_or("").to_string(),
            None => {
                debug!("No <template> found, using full source");
                source.to_string()
            }
        };
        
        let html_to_parse = if template_content.is_empty() { source } else { &template_content };
        
        // 解析 HTML
        let opts = ParseOpts::default();
        let dom = parse_fragment(
            RcDom::default(),
            opts,
            QualName::new(None, ns!(html), local_name!("body")),
            vec![],
        )
        .one(Tendril::from(html_to_parse));
        
        // 转换为 DOMNode 树
        let root = Self::convert_handle_to_dom_node(&dom.document);
        Ok(root)
    }
    
    /// 递归转换 html5ever Handle 到 DOMNode
    #[allow(dead_code)]
    fn convert_handle_to_dom_node(handle: &markup5ever_rcdom::Handle) -> DOMNode {
        use iris_layout::dom::DOMNode;
        use markup5ever_rcdom::NodeData;
        
        match &handle.data {
            NodeData::Document => {
                // 递归处理子节点
                let children = handle.children.borrow();
                if let Some(first_child) = children.first() {
                    Self::convert_handle_to_dom_node(first_child)
                } else {
                    DOMNode::new_element("div")
                }
            }
            NodeData::Element { name, attrs, .. } => {
                let tag = name.local.to_string();
                let mut node = DOMNode::new_element(&tag);
                
                // 添加属性
                let attributes = attrs.borrow();
                for attr in attributes.iter() {
                    let key = attr.name.local.to_string();
                    let value = attr.value.to_string();
                    node.set_attribute(&key, &value);
                }
                
                // 递归处理子节点
                let children = handle.children.borrow();
                for child in children.iter() {
                    let child_node = Self::convert_handle_to_dom_node(child);
                    // 只添加非空节点
                    if !Self::is_empty_node(&child_node) {
                        node.append_child(child_node);
                    }
                }
                
                node
            }
            NodeData::Text { contents } => {
                let text = contents.borrow().to_string();
                let trimmed = text.trim();
                if trimmed.is_empty() {
                    // 空文本返回空节点标记
                    DOMNode::new_element("__empty__")
                } else {
                    DOMNode::new_text(trimmed)
                }
            }
            NodeData::Comment { .. } => {
                // 注释节点跳过
                DOMNode::new_element("__empty__")
            }
            _ => DOMNode::new_element("__empty__"),
        }
    }
    
    /// 检查节点是否为空
    #[allow(dead_code)]
    fn is_empty_node(node: &DOMNode) -> bool {
        if let iris_layout::dom::NodeType::Element(tag) = &node.node_type {
            tag == "__empty__"
        } else {
            false
        }
    }

    /// 将 VTree 转换为 DOMNode 树
    ///
    /// 这是 Phase B 的关键步骤：将虚拟 DOM 转换为真实 DOM 结构
    ///
    /// # 返回
    ///
    /// 返回转换后的 DOMNode 树，可用于布局和渲染
    pub fn build_dom_from_vtree(&self) -> Option<iris_layout::dom::DOMNode> {
        self.vtree.as_ref().map(|tree| tree.to_dom_node())
    }

    /// 计算 DOM 树的布局
    ///
    /// 这是 Phase C 的核心功能：对 DOM 树应用 CSS 样式并计算布局
    ///
    /// # 流程
    ///
    /// 1. 从 VTree 构建 DOM 树（如果还没有）
    /// 2. 应用 CSS 样式
    /// 3. 计算布局（Flexbox/Block）
    /// 4. 存储布局结果
    ///
    /// # 返回
    ///
    /// 返回带有布局信息的 DOM 树
    ///
    /// # 示例
    ///
    /// ```ignore
    /// orchestrator.load_sfc_with_vtree("App.vue")?;
    /// 
    /// if let Some(dom_with_layout) = orchestrator.compute_layout()? {
    ///     // 使用带布局信息的 DOM 树进行渲染
    /// }
    /// ```
    pub fn compute_layout(&mut self) -> Result<&DOMNode, String> {
        // 开始 DevTools 布局计时
        self.dev_tools.begin_layout();
        
        // 1. 确保有 VTree
        if self.vtree.is_none() {
            return Err("No VTree available. Call load_sfc_with_vtree() first.".to_string());
        }

        // 2. 构建 DOM 树
        let dom_tree = self.build_dom_from_vtree()
            .ok_or("Failed to build DOM tree from VTree")?;
        
        self.dom_tree = Some(dom_tree);
        
        // 重建 HitTest 索引
        if let Some(ref dom_tree) = self.dom_tree {
            self.hit_index.rebuild(dom_tree);
            debug!(stats = %self.hit_index.stats(), "HitTest index rebuilt");
        }

        // 3. 获取可变的 DOM 树引用
        let dom_tree_mut = self.dom_tree.as_mut().unwrap();

        // 4. 获取样式表并计算布局
        info!(
            viewport = format!("{}x{}", self.viewport_width, self.viewport_height),
            "Computing layout..."
        );
        
        let sheet = self.css_stylesheets.get("main")
            .cloned()
            .unwrap_or(Stylesheet::new());
        compute_layout(
            dom_tree_mut,
            &sheet,
            self.viewport_width,
            self.viewport_height,
        );
        
        // 结束 DevTools 布局计时
        self.dev_tools.end_layout();
        
        info!("Layout computation completed");
        Ok(self.dom_tree.as_ref().unwrap())
    }

    /// 从外部 DOM 树计算布局（用于 HTML 入口项目）
    ///
    /// # 参数
    ///
    /// * `dom_tree` - 已经解析好的 HTML DOM 树
    /// * `stylesheet` - CSS 样式表
    ///
    /// # 示例
    ///
    /// ```ignore
    /// let dom_tree = parse_html("<div id='app'></div>");
    /// let stylesheet = parse_stylesheet("...");
    /// orchestrator.compute_layout_from_dom(dom_tree, stylesheet)?;
    /// let commands = orchestrator.generate_render_commands();
    /// ```
    pub fn compute_layout_from_dom(
        &mut self,
        dom_tree: iris_layout::dom::DOMTree,
        stylesheet: Stylesheet,
    ) -> Result<&DOMNode, String> {
        // 开始 DevTools 布局计时
        self.dev_tools.begin_layout();
        
        info!(
            viewport = format!("{}x{}", self.viewport_width, self.viewport_height),
            "Computing layout from external DOM tree..."
        );
        
        // 1. 存储 DOM 树（提取 root 节点）
        self.dom_tree = Some(dom_tree.root);
        
        // 重建 HitTest 索引
        if let Some(ref dom_tree) = self.dom_tree {
            self.hit_index.rebuild(dom_tree);
            debug!(stats = %self.hit_index.stats(), "HitTest index rebuilt from external DOM");
        }
        
        // 2. 获取可变的 DOM 树引用
        let dom_tree_mut = self.dom_tree.as_mut().unwrap();
        
        // 3. 计算布局
        compute_layout(
            dom_tree_mut,
            &stylesheet,
            self.viewport_width,
            self.viewport_height,
        );
        
        // 结束 DevTools 布局计时
        self.dev_tools.end_layout();
        
        info!("Layout computation from DOM completed");
        Ok(self.dom_tree.as_ref().unwrap())
    }

    /// 设置视口尺寸
    ///
    /// # 参数
    ///
    /// * `width` - 视口宽度
    /// * `height` - 视口高度
    pub fn set_viewport_size(&mut self, width: f32, height: f32) {
        self.viewport_width = width;
        self.viewport_height = height;
        // 同步脏矩形管理器的视口尺寸并标记全屏重绘
        self.dirty_rect_manager = DirtyRectManager::new(width, height);
        self.dirty_rect_manager.mark_full_dirty();
        // 标记布局需要重新计算
        self.layout_dirty = true;
    }

    /// 获取当前 DOM 树
    pub fn dom_tree(&self) -> Option<&DOMNode> {
        self.dom_tree.as_ref()
    }

    /// 将带布局的 DOM 树转换为渲染命令
    ///
    /// 这是 Phase D 的核心功能：遍历 DOM 树，提取布局和样式信息，
    /// 生成 GPU 渲染命令（DrawCommand）
    ///
    /// # 返回
    ///
    /// 返回渲染命令列表，可提交到 GPU 渲染器
    ///
    /// # 示例
    ///
    /// ```ignore
    /// orchestrator.compute_layout()?;
    /// let commands = orchestrator.generate_render_commands();
    /// 
    /// // 提交到 GPU 渲染器
    /// for command in commands {
    ///     batch_renderer.submit(command);
    /// }
    /// ```
    pub fn generate_render_commands(&mut self) -> Vec<DrawCommand> {
        let mut commands = Vec::new();
        
        // 开始 DevTools 渲染计时
        self.dev_tools.begin_render();
        
        // 清除旧的映射表（每帧重建）
        #[cfg(feature = "vue-sfc")]
        {
            self.command_to_node_map.clear();
            // 注意：node_to_vnode_map 不需要清除，它在 DOMNode 创建时更新
        }
        
        // 克隆 dom_tree 引用以避免借用冲突
        if let Some(dom_tree) = &self.dom_tree.clone() {
            let mut list_counter = 0usize;
            let _ = self.collect_render_commands(dom_tree, &mut commands, 0,
                0.0, 0.0, self.viewport_width, [1.0, 1.0, 1.0, 1.0], 16.0, 0, true, "left", &mut list_counter, None, "", 0.0, 1.0);
        }
        
        info!(command_count = commands.len(), "Generated render commands");

        // ========== 输出不可见元素报告（提供给 iris-cli 用户） ==========
        let reports = self.invisible_reports.borrow_mut().drain(..).collect::<Vec<_>>();
        if !reports.is_empty() {
            println!();
            println!("[Iris] 以下元素当前在视口中不可见：");
            for r in &reports {
                println!("  - {}", r);
            }
            println!("  提示：可能是布局溢出导致，考虑在容器上设置 overflow:hidden 裁剪");
            println!();
        }

        // 按 z-index 排序 DrawCommand，确保正确的层叠顺序
        commands.sort_by_key(|cmd| cmd.get_z_index());

        // 记录渲染性能到 DevTools
        self.dev_tools.end_render();
        
        commands
    }

    /// 从节点属性中提取布局数据（由 compute_layout 存储）
    fn node_layout(node: &DOMNode) -> (f32, f32, f32, f32) {
        (
            Self::parse_layout_attr(node, "__layout_x"),
            Self::parse_layout_attr(node, "__layout_y"),
            Self::parse_layout_attr(node, "__layout_width"),
            Self::parse_layout_attr(node, "__layout_height"),
        )
    }
    
    /// 解析布局属性值
    #[inline]
    fn parse_layout_attr(node: &DOMNode, key: &str) -> f32 {
        node.get_attribute(key)
            .and_then(|v| v.parse::<f32>().ok())
            .unwrap_or(0.0)
    }
    
    /// 解析元素的 padding（支持缩写和独立属性）
    fn parse_element_padding(styles: Option<&iris_layout::style::ComputedStyles>) -> (f32, f32) {
        let (mut top, mut left) = styles
            .and_then(|s| s.get("padding"))
            .map(|p| crate::css_utils::parse_css_padding(p))
            .unwrap_or((0.0, 0.0));
        
        // 独立属性覆盖缩写
        if let Some(pt) = styles.and_then(|s| s.get("padding-top")) {
            top = crate::css_utils::parse_css_unit(pt).max(0.0);
        }
        if let Some(pl) = styles.and_then(|s| s.get("padding-left")) {
            left = crate::css_utils::parse_css_unit(pl).max(0.0);
        }
        
        (top, left)
    }
    
    /// 解析元素的 margin-top（支持缩写和独立属性）
    fn parse_element_margin_top(styles: Option<&iris_layout::style::ComputedStyles>) -> f32 {
        styles
            .and_then(|s| s.get("margin-top").or_else(|| s.get("margin")))
            .and_then(|v| {
                let first = v.trim().split_whitespace().next().unwrap_or("0");
                let px = crate::css_utils::parse_css_unit(first).max(0.0);
                if px > 0.0 { Some(px) } else { None }
            })
            .unwrap_or(0.0)
    }

    /// 获取 CSS font-size 对应的字体推荐行高（ascent + descent + line_gap）
    fn get_font_line_height(&self, css_font_size: f32) -> f32 {
        if let Some(renderer) = self.gpu_renderer.as_ref() {
            if let Some(atlas) = renderer.font_atlas() {
                let scale = css_font_size / atlas.font_size();
                let line_height = atlas.font_line_height();
                // line_height 是图集基准字号下的值，按比例缩放到 CSS font-size
                if line_height > 0.0 {
                    return line_height * scale;
                }
            }
        }
        // fallback: CSS 标准默认 normal ≈ 1.2
        css_font_size * 1.2
    }

    /// 解析 box-shadow CSS 值，返回 (offset_x, offset_y, blur, color)
    fn parse_box_shadow_value(value: &str) -> Option<(f32, f32, f32, [f32; 4])> {
        let value = value.trim();
        // 跳过 inset 关键字
        let value = value.strip_prefix("inset ").unwrap_or(value);
        let parts: Vec<&str> = value.split_whitespace().collect();
        if parts.len() < 3 {
            return None;
        }
        let offset_x = parts[0].trim_end_matches("px").parse::<f32>().ok()?;
        let offset_y = parts[1].trim_end_matches("px").parse::<f32>().ok()?;
        let blur = parts[2].trim_end_matches("px").parse::<f32>().ok()?;
        // 解析颜色：可能是第4个单词，也可能包含空格（如 rgba(0,0,0,0.1)）
        let shadow_color = if parts.len() >= 4 {
            if parts[3].starts_with("rgb") {
                let rest: String = parts[3..].join(" ");
                crate::css_utils::parse_css_color(&rest)?
            } else {
                crate::css_utils::parse_css_color(parts[3])?
            }
        } else {
            [0.0, 0.0, 0.0, 0.3] // 默认半透明黑色
        };
        Some((offset_x, offset_y, blur, shadow_color))
    }

    /// 解析 text-shadow CSS 值，返回 (offset_x, offset_y, blur, color)
    /// 格式: offset-x offset-y blur-radius color（blur 和 color 可选）
    /// 示例: "0 1px 2px rgba(0,0,0,0.3)"
    fn parse_text_shadow_value(value: &str) -> Option<(f32, f32, f32, [f32; 4])> {
        let value = value.trim();
        if value.is_empty() || value == "none" {
            return None;
        }
        let parts: Vec<&str> = value.split_whitespace().collect();
        if parts.len() < 2 {
            return None;
        }
        let offset_x = parts[0].trim_end_matches("px").parse::<f32>().ok()?;
        let offset_y = parts[1].trim_end_matches("px").parse::<f32>().ok()?;
        // blur 半径（可选）：第3个参数如果以 px 结尾或无逗号可解析为数字
        let (blur, color_start) = if parts.len() >= 3 {
            if let Ok(b) = parts[2].trim_end_matches("px").parse::<f32>() {
                (b, 3)
            } else {
                (0.0, 2)
            }
        } else {
            (0.0, 2)
        };
        let shadow_color = if color_start < parts.len() {
            let color_str: &str = parts[color_start];
            if color_str.starts_with("rgb") {
                let rest: String = parts[color_start..].join(" ");
                crate::css_utils::parse_css_color(&rest)?
            } else if color_str.starts_with('#') || color_str.starts_with("hsl") {
                crate::css_utils::parse_css_color(color_str)?
            } else {
                [0.0, 0.0, 0.0, 0.3]
            }
        } else {
            [0.0, 0.0, 0.0, 0.3] // 默认半透明黑色
        };
        Some((offset_x, offset_y, blur, shadow_color))
    }

    /// 递归收集渲染命令
    fn collect_render_commands(
        &mut self,
        node: &DOMNode,
        commands: &mut Vec<DrawCommand>,
        depth: usize,
        parent_x: f32,
        parent_y: f32,
        parent_width: f32,
        inherited_color: [f32; 4],
        inherited_font_size: f32,
        z_index: i32,
        visible: bool,
        inherited_text_align: &str,
        list_counter: &mut usize, // 列表项计数器
        gradient_text_override: Option<[f32; 4]>, // 渐变文字颜色覆盖
        flex_align_items: &str,          // 父 flex 容器的 align-items 值
        flex_container_height: f32,       // 父 flex 容器的布局高度
        inherited_opacity: f32,           // 新增：继承的 opacity
    ) -> f32 {
        // 数据流完整性：记录命令起始索引
        #[cfg(feature = "vue-sfc")]
        let command_start_idx = commands.len();
        #[cfg(feature = "vue-sfc")]
        let node_id = node.id;
        // 辅助函数：对 DrawCommand 应用透明度
        fn apply_opacity_to_cmd(cmd: &mut DrawCommand, opacity: f32) {
            if opacity >= 1.0 { return; }
            match cmd {
                DrawCommand::Rect { color, .. } => color[3] *= opacity,
                DrawCommand::GradientRect { start_color, end_color, .. } => { start_color[3] *= opacity; end_color[3] *= opacity; }
                DrawCommand::Border { border_color, .. } => border_color[3] *= opacity,
                DrawCommand::RoundedRect { color, .. } => color[3] *= opacity,
                DrawCommand::BoxShadow { color, .. } => color[3] *= opacity,
                DrawCommand::Text { color, .. } => color[3] *= opacity,
                DrawCommand::RadialGradientRect { start_color, end_color, .. } => { start_color[3] *= opacity; end_color[3] *= opacity; }
                DrawCommand::Circle { color, .. } => color[3] *= opacity,
                DrawCommand::ClipRect { .. } | DrawCommand::ClipEnd { .. } => {}
                _ => {}
            }
        }
        // 处理文本节点
        if let iris_layout::dom::NodeType::Text(text) = &node.node_type {
            // visibility: hidden 跳过文本渲染
            if !visible {
                return 0.0;
            }
            // ========== CSS white-space 支持 ==========
            let styles = node.computed_styles();
            let white_space = styles.as_ref()
                .and_then(|s| s.get("white-space"))
                .map(|s| s.as_str())
                .unwrap_or("normal");
            // pre / pre-wrap: 保留空白不裁剪
            let preserve_whitespace = matches!(white_space, "pre" | "pre-wrap");
            let trimmed = if preserve_whitespace { text.as_str() } else { text.trim() };
            if !trimmed.is_empty() {
                // 文本节点无布局框，使用父元素位置
                let y = parent_y;
                
                // 获取计算样式（已在上方获取）
                let text_color = styles.as_ref()
                    .and_then(|s| s.get("color"))
                    .and_then(|c| crate::css_utils::parse_css_color(c))
                    .unwrap_or(inherited_color);
                // 渐变文字覆盖：若元素设置了 background-clip:text，使用渐变推算的文本颜色覆盖
                let effective_text_color = if let Some(override_color) = gradient_text_override {
                    override_color
                } else {
                    text_color
                };
                let font_size = styles.as_ref()
                    .and_then(|s| s.get("font-size"))
                    .and_then(|s| {
                        let val = crate::css_utils::parse_css_unit(s);
                        if val > 0.0 { Some(val) } else { None }
                    })
                    .unwrap_or(inherited_font_size);
                let text_opacity = styles.as_ref()
                    .and_then(|s| s.get("opacity"))
                    .and_then(|v| v.trim().parse::<f32>().ok())
                    .unwrap_or(1.0);
                // 修复：应用继承的 opacity
                let effective_text_opacity = inherited_opacity * text_opacity;
                let bold = styles.as_ref()
                    .and_then(|s| s.get("font-weight"))
                    .map(|w| {
                        if let Ok(n) = w.trim().parse::<u16>() {
                            n >= 600
                        } else {
                            matches!(w.as_str(), "bold" | "bolder")
                        }
                    })
                    .unwrap_or(false);
                let text_align = styles.as_ref()
                    .and_then(|s| s.get("text-align"))
                    .map(|s| s.as_str())
                    .unwrap_or(inherited_text_align);
                let line_height = styles.as_ref()
                    .and_then(|s| s.get("line-height"))
                    .map(|v| iris_layout::layout::parse_line_height(v, font_size))
                    .unwrap_or_else(|| self.get_font_line_height(font_size));
                // ========== CSS text-shadow 支持 ==========
                // 格式: offset-x offset-y blur-radius color（可选）
                let text_shadow = styles.as_ref()
                    .and_then(|s| s.get("text-shadow"))
                    .and_then(|v| Self::parse_text_shadow_value(v));
                let nowrap = white_space == "nowrap";
                let mut text_width = measure_text(trimmed, font_size);
                let mut display_text = trimmed.to_string();

                // ========== CSS text-overflow: ellipsis 支持 ==========
                // 前置条件：overflow: hidden + white-space: nowrap + width 限制
                let text_overflow = styles.as_ref()
                    .and_then(|s| s.get("text-overflow"))
                    .map(|s| s.as_str());
                let overflow_hidden = styles.as_ref()
                    .and_then(|s| s.get("overflow"))
                    .map(|s| s == "hidden")
                    .unwrap_or(false);
                let white_space_nowrap = styles.as_ref()
                    .and_then(|s| s.get("white-space"))
                    .map(|s| s == "nowrap")
                    .unwrap_or(false);
                
                if text_overflow == Some("ellipsis") && overflow_hidden && white_space_nowrap && parent_width > 0.0 && text_width > parent_width {
                    let ellipsis_width = measure_text("...", font_size);
                    let available = (parent_width - ellipsis_width).max(0.0);
                    let mut chars: Vec<char> = display_text.chars().collect();
                    while measure_text(&chars.iter().collect::<String>(), font_size) > available && chars.len() > 1 {
                        chars.pop();
                    }
                    display_text = chars.into_iter().collect();
                    display_text += "...";
                    text_width = measure_text(&display_text, font_size);
                }

                // ========== 文本换行（自然段自动换行 + CJK 字符支持） ==========
                // 将文本按单词 + CJK 字符分割，当一行超出可用宽度时自动换行
                let lines: Vec<String> = if !nowrap && !white_space_nowrap && parent_width > 0.0 && text_width > parent_width {
                    fn is_cjk_char(c: char) -> bool {
                        matches!(c,
                            '\u{4E00}'..='\u{9FFF}' | '\u{3400}'..='\u{4DBF}' | // CJK 统一表意符号
                            '\u{F900}'..='\u{FAFF}' | '\u{2F800}'..='\u{2FA1F}' | // CJK 兼容表意符号
                            '\u{3040}'..='\u{309F}' | '\u{30A0}'..='\u{30FF}' | // 平假名 + 片假名
                            '\u{AC00}'..='\u{D7AF}' | // 韩文
                            '\u{3000}'..='\u{303F}' | // CJK 符号和标点
                            '\u{FF00}'..='\u{FFEF}' | // 全角形式
                            '\u{2E80}'..='\u{2EFF}' | // CJK 部首补充
                            '\u{20000}'..='\u{2EBEF}') // CJK 扩展 B/C
                    }
                    fn split_cjk_words(text: &str) -> Vec<String> {
                        let mut result = Vec::new();
                        let mut current = String::new();
                        for c in text.chars() {
                            if c == ' ' {
                                if !current.is_empty() {
                                    result.push(current.clone());
                                    current.clear();
                                }
                            } else if is_cjk_char(c) {
                                if !current.is_empty() {
                                    result.push(current.clone());
                                    current.clear();
                                }
                                result.push(c.to_string());
                            } else {
                                current.push(c);
                            }
                        }
                        if !current.is_empty() {
                            result.push(current);
                        }
                        result
                    }
                    let max_line_width = parent_width;
                    let mut wrapped_lines: Vec<String> = Vec::new();
                    let words = split_cjk_words(&display_text);
                    let mut current_line = String::new();
                    for word in words {
                        let test_line = if current_line.is_empty() {
                            word.to_string()
                        } else {
                            format!("{} {}", current_line, word)
                        };
                        let test_width = measure_text(&test_line, font_size);
                        if test_width > max_line_width && !current_line.is_empty() {
                            // 当前行已满，换行
                            wrapped_lines.push(current_line.clone());
                            current_line = word.to_string();
                        } else {
                            current_line = test_line;
                        }
                    }
                    if !current_line.is_empty() {
                        wrapped_lines.push(current_line);
                    }
                    if wrapped_lines.is_empty() {
                        vec![display_text]
                    } else {
                        wrapped_lines
                    }
                } else {
                    vec![display_text]
                };
                
                let num_lines = lines.len();
                let mut line_y = y;

                // 父元素是 flex 容器且 align-items: center：垂直居中文本块
                if flex_align_items == "center" && flex_container_height > 0.0 && num_lines > 0 {
                    let total_text_height = num_lines as f32 * line_height;
                    let top_margin = ((flex_container_height - total_text_height) / 2.0).max(0.0);
                    line_y = parent_y + top_margin;
                }
                
                // 逐行渲染文本
                for line_text in &lines {
                    let line_width = measure_text(line_text, font_size);
                    let text_x = match text_align {
                        "center" if parent_width > 0.0 => parent_x + (parent_width - line_width) / 2.0,
                        "right" if parent_width > 0.0 => parent_x + parent_width - line_width,
                        _ => parent_x,
                    };
                    let mut final_color = effective_text_color;
                    if effective_text_opacity < 1.0 {
                        final_color[3] *= effective_text_opacity;
                    }

                    commands.push(DrawCommand::Text {
                        x: text_x,
                        y: line_y,
                        width: line_width,
                        height: font_size,
                        text: line_text.clone(),
                        color: final_color,
                        font_size,
                        bold,
                        z_index: z_index + 2, // 文字层(z_index+2)：在背景(z_index+0)和边框(z_index+1)之上
                    });
                    
                    // DEBUG: 输出文字命令详情
                    info!(
                        text = line_text,
                        x = text_x,
                        y = line_y,
                        width = line_width,
                        height = font_size,
                        font_size,
                        color = ?final_color,
                        actual_z_index = z_index + 2,
                        parent_z_index = z_index,
                        parent_x,
                        parent_y,
                        parent_width,
                        "Generated Text DrawCommand"
                    );

                    // ========== CSS text-shadow 支持 ==========
                    if let Some((shadow_ox, shadow_oy, _shadow_blur, shadow_color)) = text_shadow {
                        let shadow_x = text_x + shadow_ox;
                        let shadow_y = line_y + shadow_oy;
                        commands.push(DrawCommand::Text {
                            x: shadow_x,
                            y: shadow_y,
                            width: line_width,
                            height: font_size,
                            text: line_text.clone(),
                            color: shadow_color,
                            font_size,
                            bold,
                            z_index, // 使用相同 z_index，阴影在主文本前被推入，自然在下方
                        });
                    }

                    // ========== CSS text-decoration 支持（仅第一行） ==========
                    if num_lines == 1 || line_text == &lines[0] {
                        let text_decoration = styles.as_ref()
                            .and_then(|s| s.get("text-decoration"))
                            .map(|s| s.as_str());
                        let decoration_color = final_color;
                        let line_thickness = (font_size * 0.08).max(1.0);
                        match text_decoration {
                            Some("underline") => {
                                commands.push(DrawCommand::Rect {
                                    x: text_x,
                                    y: line_y + font_size + 1.0,
                                    width: line_width,
                                    height: line_thickness,
                                    color: decoration_color,
                                    z_index,
                                });
                            }
                            Some("line-through") => {
                                commands.push(DrawCommand::Rect {
                                    x: text_x,
                                    y: line_y + font_size * 0.45,
                                    width: line_width,
                                    height: line_thickness,
                                    color: decoration_color,
                                    z_index,
                                });
                            }
                            Some("overline") => {
                                commands.push(DrawCommand::Rect {
                                    x: text_x,
                                    y: line_y - 1.0,
                                    width: line_width,
                                    height: line_thickness,
                                    color: decoration_color,
                                    z_index,
                                });
                            }
                            _ => {}
                        }
                    }
                    
                    line_y += line_height;
                }

                return line_height * num_lines as f32; // 返回文本总行高
            }
            return 0.0;
        }
        
        // 只处理元素节点
        if !node.is_element() {
            return 0.0;
        }

        // 获取元素标签和样式
        let tag = match &node.node_type {
            iris_layout::dom::NodeType::Element(tag) => tag.clone(),
            _ => return 0.0,
        };

        let class = node.get_attribute("class").map(|s| s.as_str()).unwrap_or("");
        let style_attr = node.get_attribute("style").map(|s| s.as_str()).unwrap_or("");
        
        // 获取计算后的样式（来自CSS规则匹配）
        let computed_from_node = node.computed_styles();

        // ========== CSS 定位支持 ==========
        let pos_config = computed_from_node.as_ref()
            .map(|s| PositionConfig::from_styles(s));
        let position_type = pos_config.as_ref()
            .map(|c| c.position)
            .unwrap_or(PositionType::Static);
        let is_out_of_flow = position_type.is_out_of_flow();
        let child_z_index = pos_config.as_ref()
            .and_then(|c| c.z_index)
            .unwrap_or(z_index);

        // ========== CSS visibility 支持 ==========
        let own_visibility = computed_from_node.as_ref()
            .and_then(|s| s.get("visibility"))
            .map(|s| s.as_str());
        // child_visible: 子元素继承的可见性
        // 若父链隐藏但自身显式 visible → 可见; 若父链可见但自身 hidden → 隐藏
        let is_element_visible = match own_visibility {
            Some("hidden") if visible => false,   // 父可见 + 自身hidden = 隐藏
            Some("visible") if !visible => true,    // 父隐藏 + 自身visible = 可见
            _ => visible,                            // 否则继承父值
        };

        // 从计算样式推导继承属性（用于子节点文字）
        let child_color = computed_from_node.as_ref()
            .and_then(|s| s.get("color"))
            .and_then(|c| crate::css_utils::parse_css_color(c))
            .unwrap_or(inherited_color);
        let child_font_size = computed_from_node.as_ref()
            .and_then(|s| s.get("font-size"))
            .and_then(|s| {
                let val = crate::css_utils::parse_css_unit(s);
                if val > 0.0 { Some(val) } else { None }
            })
            .unwrap_or(inherited_font_size);
        // ========== CSS font-weight 支持 ==========
        let child_bold = computed_from_node.as_ref()
            .and_then(|s| s.get("font-weight"))
            .map(|w| {
                // 数值 >= 600 或关键字 bold/bolder 视为粗体
                if let Ok(n) = w.trim().parse::<u16>() {
                    n >= 600
                } else {
                    matches!(w.as_str(), "bold" | "bolder")
                }
            })
            .unwrap_or(false);
        let line_height = computed_from_node.as_ref()
            .and_then(|s| s.get("line-height"))
            .map(|v| iris_layout::layout::parse_line_height(v, child_font_size))
            .unwrap_or_else(|| self.get_font_line_height(child_font_size));
        let text_align = computed_from_node.as_ref()
            .and_then(|s| s.get("text-align"))
            .map(|s| s.as_str())
            .unwrap_or(inherited_text_align);
        let opacity = computed_from_node.as_ref()
            .and_then(|s| s.get("opacity"))
            .and_then(|v| v.trim().parse::<f32>().ok())
            .unwrap_or(1.0);
        // 修复：计算继承的 opacity
        let effective_opacity = inherited_opacity * opacity;

        // 使用布局引擎计算的位置（包括 margin:auto 居中、margin/padding 偏移等）
        let (lx, ly, lw, lh) = Self::node_layout(node);
        
        // DEBUG: 输出关键节点的布局信息
        if class.contains("content") || class.contains("features") || class.contains("swatches") || class.contains("text-samples") || class.contains("color-palette") || class.contains("text-demo") || class.contains("stats-row") || class.contains("app") || class.contains("typography") {
            info!(tag = %tag, class = %class, lx, ly, lw, lh, parent_x, parent_y, "NODE LAYOUT DEBUG");
        }
        
        let mut x = parent_x;
        let mut y = parent_y;
        // 使用布局引擎的尺寸数据
        // 如果布局引擎未计算宽度(为0), 回退到父容器宽度
        // 修复: flex子项无显式width时lw=0导致子文本parent_width=0
        let width = if lw != 0.0 { lw } else { parent_width };
        let height = if lh != 0.0 { lh } else { 0.0 };

        // CSS 定位偏移：absolute/fixed 重新计算位置，relative 叠加偏移
        if is_out_of_flow {
            // absolute/fixed: 脱离文档流，使用包含块计算位置
            let container_w = if parent_width > 0.0 { parent_width } else { self.viewport_width };
            let container_h = if height > 0.0 { height } else { self.viewport_height };
            if let Some(ref cfg) = pos_config {
                let abs_layout = compute_absolute_position(container_w, container_h, cfg);
                x = parent_x + abs_layout.x;
                y = parent_y + abs_layout.y;
            }
        } else if position_type == PositionType::Relative {
            // relative: 在流式布局位置上叠加 top/left 偏移
            // 先使用布局引擎的位置作为基础
            x = lx.max(parent_x);
            y = ly.max(parent_y);
            if let Some(ref cfg) = pos_config {
                let ref_w = if width > 0.0 { width } else { parent_width };
                x += cfg.left.to_pixels(ref_w);
                y += cfg.top.to_pixels(ref_w);
            }
        } else {
            // static/normal flow: 取布局引擎位置与累计位置中的较大者
            // 布局引擎处理 margin:auto 居中，累计位置包含父元素 padding
            x = lx.max(parent_x);
            y = ly.max(parent_y);
        }

        // 判断是否有显式背景 (background, background-image 或 background-color 属性)
        // CSSOM 会展开 background 缩写为 background-image + background-color + 其他子属性
        // 因此需要同时检查这三种属性（background/background-image/background-color）
        let bg_css_raw = computed_from_node.as_ref()
            .and_then(|s| s.get("background").or_else(|| s.get("background-image")).or_else(|| s.get("background-color")))
            .map(|s| s.as_str());
        let bg_css = bg_css_raw.or_else(|| {
            // 也检查 inline style 中的 background
            if style_attr.contains("background") || style_attr.contains("linear-gradient") || style_attr.contains("radial-gradient") {
                Some(style_attr)
            } else {
                None
            }
        })
        .unwrap_or("");
        
        // 检查是否为容器类元素（不再用于背景渲染，但保留用于扩展）
        let _is_container = matches!(tag.as_str(), "div" | "header" | "main" | "footer" | "section" | "nav" | "article" | "aside");
        let is_inline = matches!(tag.as_str(), "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "span" | "a" | "strong" | "em" | "b" | "i" | "code" | "small");
        
        // 背景渲染：只有显式 background 属性时才渲染
        let should_render_bg = !bg_css.is_empty();
        
        if should_render_bg && is_element_visible {
            if bg_css.contains("linear-gradient") {
                // 解析线性渐变背景（仅 Vue 模式）
                #[cfg(feature = "vue-sfc")]
                if let Some((colors, horizontal)) = crate::css_utils::parse_gradient(bg_css) {
                    if colors.len() >= 2 {
                        // 多色标渐变：将中间色标混合到终点色中，获得视觉上更准确的过渡
                        let start_color = colors[0];
                        let end_color = if colors.len() > 2 {
                            // 对中间色标取加权平均作为终点色
                            let mut blended = colors[colors.len() - 1];
                            let mid_count = (colors.len() - 2) as f32;
                            for i in 1..colors.len() - 1 {
                                let w = 1.0 / mid_count;
                                for c in 0..4 {
                                    blended[c] = blended[c] * (1.0 - w * 0.5) + colors[i][c] * (w * 0.5);
                                }
                            }
                            blended
                        } else {
                            colors[1]
                        };
                        let mut grad_cmd = DrawCommand::GradientRect {
                            x, y, width, height,
                            start_color,
                            end_color,
                            horizontal,
                            position_x: 0.0,
                            position_y: 0.0,
                            z_index: child_z_index, // 背景层: z_index+0
                        };
                        apply_opacity_to_cmd(&mut grad_cmd, effective_opacity);
                        commands.push(grad_cmd);
                    } else {
                        // 只有一个停止点时，使用同一颜色渲染为纯色
                        let mut grad_cmd = DrawCommand::GradientRect {
                            x, y, width, height,
                            start_color: colors[0],
                            end_color: colors[0],
                            horizontal: true,
                            position_x: 0.0,
                            position_y: 0.0,
                            z_index: child_z_index, // 背景层: z_index+0
                        };
                        apply_opacity_to_cmd(&mut grad_cmd, effective_opacity);
                        commands.push(grad_cmd);
                    }
                } else {
                    // 线性渐变解析失败，使用透明色（避免异常调试色）
                    commands.push(DrawCommand::GradientRect {
                        x, y, width, height,
                        start_color: [0.0, 0.0, 0.0, 0.0],
                        end_color: [0.0, 0.0, 0.0, 0.0],
                        horizontal: true,
                        position_x: 0.0,
                        position_y: 0.0,
                        z_index: child_z_index, // 背景层: z_index+0
                    });
                }
            } else if bg_css.contains("radial-gradient") {
                if let Some((center_x, center_y, radius, start_color, end_color)) = crate::css_utils::parse_radial_gradient(bg_css) {
                    let mut radial_cmd = DrawCommand::RadialGradientRect {
                        center_x: x + center_x,
                        center_y: y + center_y,
                        radius,
                        start_color,
                        end_color,
                        z_index: child_z_index, // 背景层: z_index+0
                    };
                    apply_opacity_to_cmd(&mut radial_cmd, effective_opacity);
                    commands.push(radial_cmd);
                } else {
                    // 径向渐变解析失败，使用透明色（避免异常调试色）
                    commands.push(DrawCommand::RadialGradientRect {
                        center_x: x + width / 2.0,
                        center_y: y + height / 2.0,
                        radius: width.min(height) / 2.0,
                        start_color: [0.0, 0.0, 0.0, 0.0],
                        end_color: [0.0, 0.0, 0.0, 0.0],
                        z_index: child_z_index, // 背景层: z_index+0
                    });
                }
            } else if !bg_css.is_empty() {
                // 纯色背景
                let parsed = crate::css_utils::parse_css_color(bg_css);
                let fallback_color = self.get_element_color_by_class(&tag, class, style_attr);
                let color = parsed
                    .or_else(|| Some(fallback_color))
                    .unwrap_or(self.get_element_color_by_tag(&tag));

                // 检查 border-radius 决定使用圆角矩形还是普通矩形
                let border_radius = computed_from_node.as_ref()
                    .and_then(|s| s.get("border-radius").or_else(|| s.get("border-top-left-radius")))
                    .and_then(|v| {
                        let v = v.trim();
                        if v.ends_with('%') {
                            v.strip_suffix('%')
                                .and_then(|n| n.parse::<f32>().ok())
                                .map(|p| width.min(height) * p / 100.0)
                        } else if v.ends_with("px") {
                            v.strip_suffix("px")
                                .and_then(|n| n.parse::<f32>().ok())
                        } else {
                            v.parse::<f32>().ok()
                        }
                    });
                if let Some(radius) = border_radius {
                    if radius > 0.0 {
                        let mut rounded_cmd = DrawCommand::RoundedRect {
                            x, y, width, height, radius, color,
                            z_index: child_z_index, // 背景层: z_index+0
                        };
                        apply_opacity_to_cmd(&mut rounded_cmd, effective_opacity);
                        commands.push(rounded_cmd);
                    } else {
                        let mut rect_cmd = DrawCommand::Rect { x, y, width, height, color, z_index: child_z_index }; // 背景层: z_index+0
                        apply_opacity_to_cmd(&mut rect_cmd, effective_opacity);
                        commands.push(rect_cmd);
                    }
                } else {
                    let mut rect_cmd = DrawCommand::Rect { x, y, width, height, color, z_index: child_z_index }; // 背景层: z_index+0
                    apply_opacity_to_cmd(&mut rect_cmd, effective_opacity);
                    commands.push(rect_cmd);
                }
            }
        }

        // ========== 通用元素 border 渲染 ==========
        // 标记是否已渲染边框，避免后续重复渲染
        let mut rendered_border = false;
        // 解析 border-color（优先 border-color 属性，再 border 缩写）
        let border_color = computed_from_node.as_ref()
            .and_then(|s| {
                // 尝试 border-color 属性
                if let Some(c) = s.get("border-color") {
                    return crate::css_utils::parse_css_color(c);
                }
                // 回退到 border 缩写解析: "1px solid rgba(...)" 提取颜色
                s.get("border").and_then(|b| {
                    b.split_whitespace().find_map(|p| {
                        if p.starts_with('#') || p.starts_with("rgb") || p.starts_with("rgba") {
                            crate::css_utils::parse_css_color(p)
                        } else { None }
                    })
                })
            });
        let border_width = computed_from_node.as_ref()
            .and_then(|s| {
                // 尝试 border-width 属性
                if let Some(w) = s.get("border-width") {
                    return Some(crate::css_utils::parse_border_width(w));
                }
                // 回退到 border 缩写解析: "1px solid ..." 提取 px 值
                s.get("border").and_then(|b| {
                    b.split_whitespace().find_map(|p| {
                        if p.ends_with("px") {
                            Some(crate::css_utils::parse_border_width(p))
                        } else { None }
                    })
                })
            });
        // 渲染 border（仅当有颜色且有宽度时）
        if let (Some(bc), Some(bw)) = (border_color, border_width) {
            if width > 0.0 && height > 0.0 && (bw.0 > 0.0 || bw.1 > 0.0 || bw.2 > 0.0 || bw.3 > 0.0) {
                let mut border_cmd = DrawCommand::Border {
                    x, y, width, height, border_width: bw, border_color: bc,
                    z_index: child_z_index, // 边框层: z_index+1
                };
                apply_opacity_to_cmd(&mut border_cmd, effective_opacity);
                commands.push(border_cmd);
                rendered_border = true;
            }
        }

        // 跳过 option 元素（select 内部不单独渲染 option）
        if tag.as_str() == "option" {
            return 0.0;
        }

        // <br> 换行：不渲染，仅消耗一行高度
        if tag.as_str() == "br" {
            let lh = computed_from_node.as_ref()
                .and_then(|s| s.get("line-height"))
                .map(|v| iris_layout::layout::parse_line_height(v, child_font_size))
                .unwrap_or_else(|| self.get_font_line_height(child_font_size));
            return lh;
        }

        // <hr> 水平线：渲染一条细线（visibility:hidden 跳过渲染但保留空间）
        if tag.as_str() == "hr" && is_element_visible {
            let hr_color = computed_from_node.as_ref()
                .and_then(|s| s.get("border-color").or_else(|| s.get("color")))
                .and_then(|c| crate::css_utils::parse_css_color(c))
                .unwrap_or([0.6, 0.6, 0.6, 1.0]);
            let hr_height = computed_from_node.as_ref()
                .and_then(|s| s.get("border-width"))
                .and_then(|w| w.trim().strip_suffix("px").and_then(|n| n.parse::<f32>().ok()))
                .unwrap_or(2.0);
            let margin_y = (height - hr_height).max(4.0) / 2.0;
            let hr_width = if width > 0.0 { width } else { 800.0 };
            let mut hr_cmd = DrawCommand::Rect {
                x, y: y + margin_y, width: hr_width, height: hr_height, color: hr_color,
                z_index: child_z_index,
            };
            apply_opacity_to_cmd(&mut hr_cmd, effective_opacity);
            commands.push(hr_cmd);
            return height.max(hr_height + 8.0);
        }

        // <img> 图片：渲染占位符（visibility:hidden 跳过渲染但保留空间）
        if tag.as_str() == "img" && is_element_visible {
            let alt_text = node.get_attribute("alt").map(|s| s.to_string()).unwrap_or_default();
            let img_width = node.get_attribute("width")
                .and_then(|w| w.trim().strip_suffix("px").and_then(|n| n.parse::<f32>().ok()))
                .unwrap_or(width.max(80.0));
            let img_height = node.get_attribute("height")
                .and_then(|h| h.trim().strip_suffix("px").and_then(|n| n.parse::<f32>().ok()))
                .unwrap_or(height.max(60.0));
            // 渲染占位矩形 + alt 文字
            let mut img_rect_cmd = DrawCommand::Rect {
                x, y, width: img_width, height: img_height,
                color: [0.85, 0.85, 0.85, 1.0],
                z_index: child_z_index, // 图标层: z_index+3（占位背景）
            };
            apply_opacity_to_cmd(&mut img_rect_cmd, effective_opacity);
            commands.push(img_rect_cmd);
            let display_text = if alt_text.is_empty() { "[img]".to_string() } else { alt_text };
            let img_text_width = measure_text(&display_text, child_font_size);
            let img_text_x = match text_align {
                "center" if img_width > 0.0 => x + (img_width - img_text_width) / 2.0,
                "right" if img_width > 0.0 => x + img_width - img_text_width - 4.0,
                _ => x + 4.0,
            };
            let mut img_text_cmd = DrawCommand::Text {
                x: img_text_x,
                y: y + (img_height - child_font_size).max(0.0) / 2.0,
                width: img_text_width,
                height: child_font_size,
                text: display_text,
                color: [0.3, 0.3, 0.3, 1.0],
                font_size: child_font_size,
                bold: child_bold,
                z_index: child_z_index, // 图标层: z_index+3（alt 文字）
            };
            apply_opacity_to_cmd(&mut img_text_cmd, effective_opacity);
            commands.push(img_text_cmd);
            return img_height;
        }

        // select 元素：渲染背景 + 第一项文字，跳过子节点递归（visibility:hidden 跳过渲染但保留空间）
        if tag.as_str() == "select" && is_element_visible {
            // 获取第一个 option 的文本
            let first_option_text = node.children.iter().find_map(|child| {
                if let iris_layout::dom::NodeType::Element(t) = &child.node_type {
                    if t == "option" {
                        return child.children.first().and_then(|c| {
                            if let iris_layout::dom::NodeType::Text(s) = &c.node_type {
                                Some(s.trim().to_string())
                            } else { None }
                        });
                    }
                }
                None
            }).unwrap_or_default();
            if !first_option_text.is_empty() {
                let (pt, pl) = computed_from_node.as_ref()
                    .and_then(|s| s.get("padding"))
                    .map(|p| crate::css_utils::parse_css_padding(p))
                    .unwrap_or((0.0, 0.0));
                let select_text_color = child_color;
                let select_font_size = child_font_size;
                let select_text_width = measure_text(&first_option_text, select_font_size);
                let select_text_x = match text_align {
                    "center" if width > 0.0 => x + pl + (width - pl * 2.0 - select_text_width) / 2.0,
                    "right" if width > 0.0 => x + width - pl - select_text_width,
                    _ => x + pl,
                };
                let mut select_text_cmd = DrawCommand::Text {
                    x: select_text_x,
                    y: y + pt,
                    width: select_text_width,
                    height: select_font_size,
                    text: first_option_text,
                    color: select_text_color,
                    font_size: select_font_size,
                    bold: child_bold,
                    z_index: child_z_index, // 文字层: z_index+2
                };
                apply_opacity_to_cmd(&mut select_text_cmd, effective_opacity);
                commands.push(select_text_cmd);
            }
            return height;
        }

        // input 元素：渲染背景 + value/placeholder 文字（visibility:hidden 跳过渲染但保留空间）
        if tag.as_str() == "input" && is_element_visible {
            let input_type = node.get_attribute("type").map(|s| s.as_str()).unwrap_or("text");
            // 文件/颜色/范围等类型输入暂不渲染特殊 UI，仅渲染文本
            if matches!(input_type, "text" | "password" | "email" | "number" | "search" | "url" | "tel" | "") {
                let input_text = node.get_attribute("value")
                    .or_else(|| node.get_attribute("placeholder"))
                    .map(|s| s.to_string())
                    .unwrap_or_default();
                if !input_text.is_empty() {
                    let (pt, pl) = computed_from_node.as_ref()
                        .and_then(|s| s.get("padding"))
                        .map(|p| crate::css_utils::parse_css_padding(p))
                        .unwrap_or((2.0, 4.0));
                    let input_text_width = measure_text(&input_text, child_font_size);
                    let input_text_x = match text_align {
                        "center" if width > 0.0 => x + pl + (width - pl * 2.0 - input_text_width) / 2.0,
                        "right" if width > 0.0 => x + width - pl - input_text_width,
                        _ => x + pl,
                    };
                    let mut input_text_cmd = DrawCommand::Text {
                        x: input_text_x,
                        y: y + pt,
                        width: input_text_width,
                        height: child_font_size,
                        text: input_text,
                        color: child_color,
                        font_size: child_font_size,
                        bold: child_bold,
                        z_index: child_z_index, // 文字层: z_index+2
                    };
                    apply_opacity_to_cmd(&mut input_text_cmd, effective_opacity);
                    commands.push(input_text_cmd);
                }
            }
            // 渲染 input 边框（UA 默认样式）
            let border_color = computed_from_node.as_ref()
                .and_then(|s| s.get("border-color"))
                .and_then(|c| crate::css_utils::parse_css_color(c))
                .unwrap_or([0.6, 0.6, 0.6, 1.0]);
            let border_width = computed_from_node.as_ref()
                .and_then(|s| s.get("border-width"))
                .map(|w| crate::css_utils::parse_border_width(w))
                .unwrap_or((1.0, 1.0, 1.0, 1.0));
            if width > 0.0 && height > 0.0 {
                let mut border_cmd = DrawCommand::Border {
                    x, y, width, height, border_width, border_color,
                    z_index: child_z_index,
                };
                apply_opacity_to_cmd(&mut border_cmd, effective_opacity);
                commands.push(border_cmd);
            }
            return height;
        }

        // button 元素：渲染背景 + 文字内容（visibility:hidden 跳过渲染但保留空间）
        if tag.as_str() == "button" && is_element_visible {
            let button_text = node.children.iter().find_map(|child| {
                if let iris_layout::dom::NodeType::Text(s) = &child.node_type {
                    Some(s.trim().to_string())
                } else { None }
            }).unwrap_or_default();
            if !button_text.is_empty() {
                let (pt, pl) = computed_from_node.as_ref()
                    .and_then(|s| s.get("padding"))
                    .map(|p| crate::css_utils::parse_css_padding(p))
                    .unwrap_or((4.0, 8.0));
                let button_text_width = measure_text(&button_text, child_font_size);
                let button_text_x = match text_align {
                    "center" if width > 0.0 => x + pl + (width - pl * 2.0 - button_text_width) / 2.0,
                    "right" if width > 0.0 => x + width - pl - button_text_width,
                    _ => x + pl,
                };
                let mut button_text_cmd = DrawCommand::Text {
                    x: button_text_x,
                    y: y + pt,
                    width: button_text_width,
                    height: child_font_size,
                    text: button_text,
                    color: child_color,
                    font_size: child_font_size,
                    bold: child_bold,
                    z_index: child_z_index, // 文字层: z_index+2
                };
                apply_opacity_to_cmd(&mut button_text_cmd, effective_opacity);
                commands.push(button_text_cmd);
            }
            // 渲染 button 边框
            let border_color = computed_from_node.as_ref()
                .and_then(|s| s.get("border-color"))
                .and_then(|c| crate::css_utils::parse_css_color(c))
                .unwrap_or([0.5, 0.5, 0.5, 1.0]);
            let border_width = computed_from_node.as_ref()
                .and_then(|s| s.get("border-width"))
                .map(|w| crate::css_utils::parse_border_width(w))
                .unwrap_or((1.0, 1.0, 1.0, 1.0));
            if width > 0.0 && height > 0.0 {
                let mut border_cmd = DrawCommand::Border {
                    x, y, width, height, border_width, border_color,
                    z_index: child_z_index,
                };
                apply_opacity_to_cmd(&mut border_cmd, effective_opacity);
                commands.push(border_cmd);
            }
            return height;
        }

        // textarea 元素：渲染背景 + 文字内容（visibility:hidden 跳过渲染但保留空间）
        if tag.as_str() == "textarea" && is_element_visible {
            let textarea_text = node.children.iter().find_map(|child| {
                if let iris_layout::dom::NodeType::Text(s) = &child.node_type {
                    Some(s.trim().to_string())
                } else { None }
            }).unwrap_or_default();
            if !textarea_text.is_empty() {
                let (pt, pl) = computed_from_node.as_ref()
                    .and_then(|s| s.get("padding"))
                    .map(|p| crate::css_utils::parse_css_padding(p))
                    .unwrap_or((4.0, 4.0));
                let textarea_text_width = measure_text(&textarea_text, child_font_size);
                let textarea_text_x = match text_align {
                    "center" if width > 0.0 => x + pl + (width - pl * 2.0 - textarea_text_width) / 2.0,
                    "right" if width > 0.0 => x + width - pl - textarea_text_width,
                    _ => x + pl,
                };
                let mut textarea_text_cmd = DrawCommand::Text {
                    x: textarea_text_x,
                    y: y + pt,
                    width: textarea_text_width,
                    height: child_font_size,
                    text: textarea_text,
                    color: child_color,
                    font_size: child_font_size,
                    bold: child_bold,
                    z_index: child_z_index,
                };
                apply_opacity_to_cmd(&mut textarea_text_cmd, opacity);
                commands.push(textarea_text_cmd);
            }
            // 渲染 textarea 边框
            let border_color = computed_from_node.as_ref()
                .and_then(|s| s.get("border-color"))
                .and_then(|c| crate::css_utils::parse_css_color(c))
                .unwrap_or([0.6, 0.6, 0.6, 1.0]);
            let border_width = computed_from_node.as_ref()
                .and_then(|s| s.get("border-width"))
                .map(|w| crate::css_utils::parse_border_width(w))
                .unwrap_or((1.0, 1.0, 1.0, 1.0));
            if width > 0.0 && height > 0.0 {
                let mut border_cmd = DrawCommand::Border {
                    x, y, width, height, border_width, border_color,
                    z_index: child_z_index,
                };
                apply_opacity_to_cmd(&mut border_cmd, effective_opacity);
                commands.push(border_cmd);
            }
            return height;
        }

        // 通用：非表单控件的边框渲染（仅当尚未通过标准 border 解析渲染时）
        if !rendered_border {
            let has_border = computed_from_node.as_ref()
                .and_then(|s| s.get("border-width").or_else(|| s.get("border")))
                .is_some();
            if has_border && is_element_visible && width > 0.0 && height > 0.0 {
                let border_color = computed_from_node.as_ref()
                    .and_then(|s| s.get("border-color"))
                    .and_then(|c| crate::css_utils::parse_css_color(c))
                    .unwrap_or([0.3, 0.3, 0.3, 1.0]);
                let border_width = computed_from_node.as_ref()
                    .and_then(|s| s.get("border-width"))
                    .map(|w| crate::css_utils::parse_border_width(w))
                    .unwrap_or((1.0, 1.0, 1.0, 1.0));
                let mut border_cmd = DrawCommand::Border {
                    x, y, width, height, border_width, border_color,
                    z_index: child_z_index,
                };
                apply_opacity_to_cmd(&mut border_cmd, effective_opacity);
                commands.push(border_cmd);
            }
        }

        // box-shadow 阴影渲染（visibility:hidden 跳过）
        if is_element_visible {
            if let Some(box_shadow) = computed_from_node.as_ref()
                .and_then(|s| s.get("box-shadow"))
            {
                if let Some((offset_x, offset_y, blur, shadow_color)) = Self::parse_box_shadow_value(box_shadow) {
                    if width > 0.0 && height > 0.0 {
                    let mut shadow_cmd = DrawCommand::BoxShadow {
                        x, y, width, height,
                        offset_x, offset_y, blur, color: shadow_color,
                        inset: false,
                        z_index: child_z_index,
                    };
                    apply_opacity_to_cmd(&mut shadow_cmd, opacity);
                    commands.push(shadow_cmd);
                }
            }
            }
        }

        // ========== CSS list-style 列表标记支持 ==========
        if tag.as_str() == "li" && is_element_visible {
            let list_style_type = computed_from_node.as_ref()
                .and_then(|s| s.get("list-style-type"))
                .map(|s| s.as_str())
                .unwrap_or("disc");
            let marker = match list_style_type {
                "circle" => "○".to_string(),
                "square" => "■".to_string(),
                "decimal" => {
                    *list_counter += 1;
                    format!("{}.", list_counter)
                }
                "none" => "".to_string(),
                _ => "•".to_string(), // disc 默认
            };
            if !marker.is_empty() {
                let marker_width = measure_text(&marker, child_font_size);
                let marker_x = (x - marker_width - 8.0).max(0.0);
                // 考虑 padding-top 对 marker 垂直位置的影响
                let padding_top = computed_from_node.as_ref()
                    .and_then(|s| s.get("padding-top"))
                    .and_then(|v| v.parse::<f32>().ok())
                    .unwrap_or(0.0);
                let marker_y = y + padding_top;
                commands.push(DrawCommand::Text {
                    x: marker_x,
                    y: marker_y,
                    width: marker_width,
                    height: child_font_size,
                    text: marker.to_string(),
                    color: child_color,
                    font_size: child_font_size,
                    bold: false,
                    z_index: child_z_index,
                });
            }
        }

        // 判断是否为 flex 容器（flex 布局的子节点位置由布局引擎计算）
        let is_flex = computed_from_node.as_ref()
            .and_then(|s| s.get("display"))
            .map(|d| d == "flex")
            .unwrap_or(false)
            // 表格相关元素也使用 flex 布局位置
            || matches!(tag.as_str(), "tr" | "table" | "thead" | "tbody" | "tfoot");
        
        // DEBUG: 输出 flex 布局信息
        if is_flex {
            info!(tag = %tag, class = %class, is_flex, width, height, "Flex container detected");
        }

        // ========== CSS overflow: hidden 裁剪支持 ==========
        let overflow_hidden = computed_from_node.as_ref()
            .and_then(|s| s.get("overflow"))
            .map(|v| v == "hidden")
            .unwrap_or(false);
        if overflow_hidden && width > 0.0 && height > 0.0 {
            commands.push(DrawCommand::ClipRect {
                x, y, width, height,
                z_index: child_z_index,
            });
        }

        // ========== 不可见元素检测（超出视口范围的元素） ==========
        if is_element_visible && width > 0.0 && height > 0.0 {
            let window_w = self.viewport_width;
            let window_h = self.viewport_height;
            let reason = if y >= window_h || y + height <= 0.0 {
                Some(format!("超出视口底部边界 (y={:.0}, height={:.0}, 视口高={:.0})", y, height, window_h))
            } else if x >= window_w || x + width <= 0.0 {
                Some(format!("超出视口右侧边界 (x={:.0}, width={:.0}, 视口宽={:.0})", x, width, window_w))
            } else if overflow_hidden && (y + height > window_h || x + width > window_w) {
                Some(format!("因父容器 overflow:hidden 被裁剪 (位置=({:.0},{:.0}), 尺寸={}x{})", x, y, width, height))
            } else {
                None
            };
            if let Some(reason) = reason {
                let id = node.get_attribute("id").map(|s| s.to_string()).unwrap_or_default();
                let tag_str = tag.to_string();
                let class_str = class.to_string();
                let tag_with_info = if !id.is_empty() {
                    format!("<{}#{}>", tag_str, id)
                } else if !class_str.is_empty() {
                    let first_class = class_str.split_whitespace().next().unwrap_or("");
                    format!("<{}.{}>", tag_str, first_class)
                } else {
                    format!("<{}>", tag_str)
                };
                self.invisible_reports.borrow_mut().push(format!("{} - {}", tag_with_info, reason));
            }
        }

        // 递归处理子节点（累加 Y 偏移或使用 flex 布局位置）
        let (padding_top, padding_left) = Self::parse_element_padding(computed_from_node.as_ref());
        let margin_top = Self::parse_element_margin_top(computed_from_node.as_ref());
        
        let child_start_x = x + padding_left;
        let child_start_y = y + padding_top + margin_top;
        
        // ========== CSS background-clip: text 渐变文字支持 ==========
        // 检测元素是否设置了渐变文字：background-clip: text + linear-gradient
        #[cfg(feature = "vue-sfc")]
        let child_gradient_override: Option<[f32; 4]> = (|| {
            let styles = computed_from_node.as_ref()?;
            let clip = styles.get("background-clip").or_else(|| styles.get("-webkit-background-clip"));
            let color_is_transparent = styles.get("color").map(|c| c.trim() == "transparent").unwrap_or(false);
            if !clip.map(|c| c.trim() == "text").unwrap_or(false) || !color_is_transparent {
                return None;
            }
            // 查找 bg 字符串：优先 computed_styles 中的 background/background-image，再尝试 style 属性
            // CSSOM 展开 background 缩写时，渐变值保存在 background-image 中而非 background
            let bg_str: &str = if let Some(bg) = styles.get("background").or_else(|| styles.get("background-image")).or_else(|| styles.get("background-color")) {
                bg.as_str()
            } else if style_attr.contains("linear-gradient") {
                style_attr
            } else {
                return None;
            };
            let (colors, _horizontal) = crate::css_utils::parse_gradient(bg_str)?;
            if colors.len() < 2 || width <= 0.0 {
                return None;
            }
            // 在元素中心位置计算渐变颜色
            let t = 0.5;
            let num_segs = colors.len() - 1;
            let seg = ((t * num_segs as f32) as usize).min(num_segs - 1);
            let seg_t = t * num_segs as f32 - seg as f32;
            let mut result = [0.0; 4];
            for i in 0..4 {
                result[i] = colors[seg][i] * (1.0 - seg_t) + colors[seg + 1][i] * seg_t;
            }
            if result[3] > 0.01 { Some(result) } else { None }
        })();
        
        #[cfg(not(feature = "vue-sfc"))]
        let child_gradient_override: Option<[f32; 4]> = None;
        
        // 计算当前元素的 flex 对齐信息（传递给子节点用于文本居中）
        let (current_flex_align, current_flex_height) = if is_flex {
            (
                computed_from_node.as_ref()
                    .and_then(|s| s.get("align-items"))
                    .map(|s| s.as_str())
                    .unwrap_or(""),
                height
            )
        } else {
            ("", 0.0)
        };
        
        // 流式布局：维护累积的 x/y 位置
        // 注意：只有 inline 元素在 x 方向累加，block 元素在 y 方向累加
        let mut flow_y = child_start_y;
        
        for child in &node.children {
            let (child_x, child_y_pos) = if is_flex {
                // flex 布局：使用布局引擎计算的子节点位置 + 容器偏移
                let (clx, cly, _, _) = Self::node_layout(child);
                (x + clx, y + cly)
            } else {
                // 流式布局：使用累积的位置（block 元素 x 不累加）
                (child_start_x, flow_y)
            };
            let consumed = self.collect_render_commands(child, commands, depth + 1,
                child_x, child_y_pos, width,
                child_color, child_font_size,
                child_z_index, is_element_visible, text_align, list_counter, child_gradient_override,
                current_flex_align, current_flex_height, effective_opacity);
            
            // 流式布局：累加 Y 位置到下一个兄弟节点
            if !is_flex {
                let child_height = Self::parse_layout_attr(child, "__layout_height");
                // 使用子节点高度或 consumed（文本节点的渲染高度）
                let actual_height = if child_height > 0.0 { child_height } else { consumed };
                flow_y += actual_height;
            }
        }

        // 关闭 overflow: hidden 裁剪区域
        if overflow_hidden && width > 0.0 && height > 0.0 {
            commands.push(DrawCommand::ClipEnd {
                z_index: child_z_index,
            });
        }

        // 返回此节点消耗的高度（absolute/fixed 脱离文档流，返回 0）
        // 修复：flex 容器的 children 使用 node_layout 位置而非 flow_y 累加，
        // 因此 flow_y - y 始终为 padding 值，无法反映实际内容高度。
        // 应使用布局引擎计算的高度（height）作为消耗高度。
        let consumed_height = if is_flex && height > 0.0 {
            height
        } else if is_out_of_flow {
            0.0
        } else if is_inline && !should_render_bg {
            line_height
        } else if should_render_bg {
            height.max(flow_y - y)
        } else {
            (flow_y - y).max(line_height)
        };
        
        // 数据流完整性：建立命令索引到节点 ID 的映射
        #[cfg(feature = "vue-sfc")]
        {
            let command_end_idx = commands.len();
            for idx in command_start_idx..command_end_idx {
                self.command_to_node_map.insert(idx, node_id);
            }
            
            // 记录 vnode_id 映射
            if let Some(vnode_id) = node.get_attribute("_vnodeId") {
                self.node_to_vnode_map.insert(node_id, vnode_id.clone());
            }
        }
        
        consumed_height
    }
    
    /// 根据 class 获取元素颜色
    fn get_element_color_by_class(&self, tag: &str, class: &str, style: &str) -> [f32; 4] {
        // 检查 class 名称
        match class {
            "app" => [0.1, 0.1, 0.15, 1.0],  // 深色背景
            "header" => {
                if style.contains("backdrop-filter") {
                    [0.4, 0.3, 0.8, 0.15]  // 毛玻璃效果
                } else {
                    [0.4, 0.3, 0.8, 0.8]
                }
            }
            "content" => [0.15, 0.15, 0.2, 1.0],
            "card" => {
                if style.contains("backdrop-filter") {
                    [0.9, 0.9, 0.9, 0.1]  // 毛玻璃卡片
                } else {
                    [0.2, 0.2, 0.25, 0.9]
                }
            }
            "subtitle" => [0.7, 0.7, 0.8, 0.9],
            _ => self.get_element_color_by_tag(tag),
        }
    }
    
    /// 根据标签获取元素颜色
    fn get_element_color_by_tag(&self, tag: &str) -> [f32; 4] {
        match tag {
            "div" => [0.4, 0.5, 0.9, 1.0],  // 蓝色
            "header" => [0.4, 0.3, 0.8, 1.0],  // 紫色
            "main" => [0.3, 0.6, 0.4, 1.0],  // 绿色
            "footer" => [0.6, 0.3, 0.4, 1.0],  // 红色
            "h1" => [0.0, 0.0, 0.0, 0.0],  // 透明（只渲染文本）
            "h2" => [0.0, 0.0, 0.0, 0.0],  // 透明
            "p" => [0.0, 0.0, 0.0, 0.0],  // 透明
            "span" => [0.0, 0.0, 0.0, 0.0],  // 透明
            "ul" | "li" => [0.0, 0.0, 0.0, 0.0],  // 透明
            _ => [0.6, 0.6, 0.6, 1.0],  // 灰色
        }
    }

    /// 标记需要重新渲染
    ///
    /// 当状态发生变化时调用此方法，触发下一帧的渲染
    pub fn mark_dirty(&mut self) {
        self.dirty = true;
        debug!("Marked renderer as dirty");
    }

    /// 检查是否需要渲染
    pub fn is_dirty(&self) -> bool {
        self.dirty
    }

    /// 计算并限制帧率
    ///
    /// # 返回
    ///
    /// 返回是否应该渲染当前帧（基于目标 FPS）
    fn should_render_frame(&mut self) -> bool {
        let now = Instant::now();
        
        // 如果是第一帧，直接渲染
        if self.last_frame_time.is_none() {
            self.last_frame_time = Some(now);
            return true;
        }
        
        let last_time = self.last_frame_time.unwrap();
        let elapsed = now.duration_since(last_time);
        
        // 计算目标帧间隔
        let target_frame_duration = std::time::Duration::from_secs_f64(1.0 / self.target_fps as f64);
        
        // 如果还没到下一帧的时间，不渲染
        if elapsed < target_frame_duration {
            return false;
        }
        
        // 更新帧率统计
        self.current_fps = 1.0 / elapsed.as_secs_f64();
        self.last_frame_time = Some(now);
        
        true
    }

    /// 执行一帧的渲染流程
    ///
    /// 这是 Phase E 的核心方法：整合所有子系统，完成一帧的完整渲染
    ///
    /// # 流程
    ///
    /// 1. 检查是否需要渲染（帧率限制 + 脏标志）
    /// 2. 执行 JavaScript（响应式更新、动画等）
    /// 3. 重新计算布局（如果 DOM 有变化）
    /// 4. 生成渲染命令
    /// 5. 提交到 GPU 渲染器
    /// 6. 清除脏标志
    ///
    /// # 返回
    ///
    /// 返回是否实际执行了渲染
    ///
    /// # 示例
    ///
    /// ```ignore
    /// // 在主循环中调用
    /// loop {
    ///     if orchestrator.render_frame() {
    ///         // 实际执行了渲染
    ///     }
    ///     
    ///     // 处理事件...
    /// }
    /// ```
    /// 将 EventData 序列化为 JSON 字符串（不使用 serde_json）
    #[cfg(feature = "vue-sfc")]
    fn serialize_event_data(data: &EventData) -> String {
        match data {
            EventData::Mouse(m) => {
                format!(
                    "{{\"x\":{},\"y\":{},\"button\":{},\"ctrlKey\":{},\"shiftKey\":{},\"altKey\":{}}}",
                    m.x, m.y, m.button, m.ctrl_key, m.shift_key, m.alt_key
                )
            }
            EventData::Keyboard(k) => {
                format!(
                    "{{\"keyCode\":{},\"key\":\"{}\",\"ctrlKey\":{},\"shiftKey\":{},\"altKey\":{}}}",
                    k.key_code, Self::json_escape(&k.key), k.ctrl_key, k.shift_key, k.alt_key
                )
            }
EventData::None => String::new(),
            EventData::Custom(s) => s.clone(),
            _ => String::new(),
        }
    }
   
    /// 对字符串中的特殊字符进行 JSON 转义，确保生成的 JSON 字符串值合法
    fn json_escape(s: &str) -> String {
        s.replace("\\", "\\\\")
         .replace('"', "\\\"")
         .replace('\n', "\\n")
         .replace('\r', "\\r")
         .replace('\t', "\\t")
    }

   /// 检查事件类型是否在 _eventTypes JSON 中（避免 contains() 误匹配）
    ///
    /// _eventTypes 格式: 可以是 JSON 对象 `{"click":true,"input":true}`
    /// 或逗号分隔字符串 `"click,input"`
    fn check_event_type_in_json(json: &str, event_type: &str) -> bool {
        if json.starts_with('{') {
            // JSON 对象格式: {"click":true,"input":true}
            json.contains(&format!("\"{}\"", event_type))
        } else if json.starts_with('[') {
            // JSON 数组格式: ["click","input"]
            json.contains(&format!("\"{}\"", event_type))
        } else {
            // 逗号分隔字符串或单个事件类型
            json.split(',').any(|s| s.trim() == event_type)
        }
    }

    /// 构建 VTree 节点信息映射（vnode_id -> (parent_vnode_id, depth, has_event_type)）
    fn collect_bubble_node_info(
        node: &iris_layout::vdom::VNode,
        event_type_str: &str,
        depth: usize,
        nodes: &mut HashMap<String, (Option<String>, usize, bool)>,
    ) {
        if let iris_layout::vdom::VNode::Element(elem) = node {
            let vnode_id = elem.attrs.get("_vnodeId").cloned();
            if let Some(vid) = vnode_id {
                let parent_id = elem.attrs.get("_parentVnodeId").cloned();
                let has_event = elem.attrs.get("_eventTypes")
                    .map(|json| Self::check_event_type_in_json(json, event_type_str))
                    .unwrap_or(false);
                nodes.insert(vid, (parent_id, depth, has_event));
            }
            for child in &elem.children {
                Self::collect_bubble_node_info(child, event_type_str, depth + 1, nodes);
            }
        }
    }

    /// 为匹配事件类型的节点构建冒泡调用顺序
    fn build_bubble_order(
        nodes: &HashMap<String, (Option<String>, usize, bool)>,
    ) -> Vec<String> {
        // 找出所有拥有匹配事件类型的节点
        let mut matching: Vec<(usize, String)> = nodes.iter()
            .filter(|(_, (_, _, has_event))| *has_event)
            .map(|(vid, (_, depth, _))| (*depth, vid.clone()))
            .collect();

        if matching.is_empty() {
            return Vec::new();
        }

        // 按深度降序排列（最深节点最先触发）
        matching.sort_by(|a, b| b.0.cmp(&a.0));

        // 为每个匹配节点构建冒泡路径（节点本身 → 父 → 祖父 → ...）
        let mut ordered = Vec::new();
        let mut seen = HashSet::new();

        for (_, vnode_id) in &matching {
            if seen.contains(vnode_id) {
                continue;
            }

            // 沿 _parentVnodeId 向上构建路径
            let mut current = vnode_id.clone();
            loop {
                if seen.contains(&current) {
                    break;
                }
                ordered.push(current.clone());
                seen.insert(current.clone());

                if let Some((Some(parent), _, _)) = nodes.get(&current) {
                    current = parent.clone();
                } else {
                    break;
                }
            }
        }

        ordered
    }

    /// 处理待处理的事件队列（支持从目标节点到根的冒泡）
    #[cfg(feature = "vue-sfc")]
    pub fn process_pending_events(&mut self) {
        let events: Vec<Event> = self.pending_events.drain(..).collect();
        for event in events {
            // 1. 分发给 Rust 侧监听器（支持 VTree 冒泡的事件代理）
            if let Some(ref vtree) = self.vtree {
                self.event_dispatcher.dispatch_with_vtree(&event, &vtree.root);
            } else {
                self.event_dispatcher.dispatch(&event);
            }

            // 2. 通过 JS 桥接实现事件冒泡（如果有 VTree）
            if let Some(vtree) = self.vtree.clone() {
                let event_type_str = event.event_type.as_str();
                let data_json = Self::serialize_event_data(&event.data);

                // 构建节点信息映射
                let mut node_infos: HashMap<String, (Option<String>, usize, bool)> = HashMap::new();
                Self::collect_bubble_node_info(
                    &vtree.root,
                    event_type_str,
                    0,
                    &mut node_infos,
                );

                // 构建冒泡顺序（最深节点 → 父 → 祖父 → ...）
                let ordered_ids = Self::build_bubble_order(&node_infos);

                // 记录已停止传播的节点，其祖先将被跳过
                let mut propagation_stopped_nodes: HashSet<String> = HashSet::new();

                for vnode_id in &ordered_ids {
                    // 检查该节点是否是某个已停止节点的祖先
                    let should_skip = propagation_stopped_nodes.iter().any(|stopped_id| {
                        let mut current = stopped_id.clone();
                        loop {
                            if current == *vnode_id {
                                return true;
                            }
                            if let Some((Some(parent), _, _)) = node_infos.get(&current) {
                                current = parent.clone();
                            } else {
                                break;
                            }
                        }
                        false
                    });

                    if should_skip {
                        continue;
                    }

                    let data_arg = if data_json.is_empty() {
                        "null".to_string()
                    } else {
                        // 直接作为 JS 对象字面量传递，不再包裹为字符串
                        data_json.clone()
                    };

                    // 传递 Rust 侧的事件状态到 JS 桥接
                    let default_prevented = event.is_default_prevented();
                    let propagation_stopped = event.is_propagation_stopped();
                    let js_call = format!(
                        "globalThis.__iris_invokeEventHandler('{}', '{}', {}, {}, {})",
                        vnode_id, event_type_str, data_arg,
                        if default_prevented { "true" } else { "false" },
                        if propagation_stopped { "true" } else { "false" }
                    );

                    if let Ok(result) = self.js_runtime.eval(&js_call) {
                        if result.as_boolean().unwrap_or(false) {
                            // 传播已停止，记录该节点
                            propagation_stopped_nodes.insert(vnode_id.clone());
                        }
                    }
                }
            }
        }

        // 3. 检查响应式脏标记，更新 VTree
        if check_reactive_dirty(&mut self.js_runtime) {
            if let Err(e) = self.update_vtree_from_reactive() {
                warn!(error = %e, "Failed to update vtree from reactive");
            }
            clear_reactive_dirty(&mut self.js_runtime);
            self.dirty = true;
        }
    }

    /// 将事件加入待处理队列
    ///
    /// 事件将在下一帧 render_frame() 中被处理。
    /// 同时会标记 dirty 以确保帧渲染被触发。
    #[cfg(feature = "vue-sfc")]
    pub fn queue_event(&mut self, event: Event) {
        self.pending_events.push(event);
        self.dirty = true;
        debug!(queue_len = self.pending_events.len(), "Event queued");
    }

    /// 执行一帧的渲染流程
    ///
    /// 这是 Phase E 的核心方法：整合所有子系统，完成一帧的完整渲染
    ///
    /// # 流程
    ///
    /// 1. 处理待处理事件队列
    /// 2. 检查是否需要渲染（帧率限制 + 脏标志）
    /// 3. 执行 JavaScript（响应式更新、动画等）
    /// 4. 重新计算布局（如果 DOM 有变化）
    /// 5. 生成渲染命令
    /// 6. 提交到 GPU 渲染器
    /// 7. 清除脏标志
    ///
    /// # 返回
    ///
    /// 返回是否实际执行了渲染
    pub fn render_frame(&mut self) -> bool {
        // 0. 处理 HMR 事件（文件变更检测 → 热重载 → 标记脏标志）
        self.process_hmr_events();

        // 1. 处理待处理事件队列（仅 Vue 模式）
        #[cfg(feature = "vue-sfc")]
        self.process_pending_events();

        // 2. 检查是否应该继续渲染（ErrorBoundary）
        if !self.error_boundary.should_continue_rendering() {
            warn!("Render blocked by ErrorBoundary");
            return false;
        }
        
        // 2. 检查帧率限制
        if !self.should_render_frame() {
            return false;
        }
        
        // 3. 检查脏标志
        if !self.dirty {
            return false;
        }
        
        // 4. 开始 DevTools 帧计时（确定渲染时才计时）
        self.dev_tools.begin_frame();
        
        info!(
            fps = format!("{:.1}", self.current_fps),
            "Rendering frame..."
        );
        
        // 5. 更新动画
        let _has_animations = self.update_animations();
        
        // 6. 如果视口尺寸变化，重新计算布局
        if self.layout_dirty {
            let sheet = self.css_stylesheets.get("main")
                .cloned()
                .unwrap_or(iris_layout::css::Stylesheet::new());
            let vp_w = self.viewport_width;
            let vp_h = self.viewport_height;
            if let Some(ref mut dom_tree) = self.dom_tree {
                compute_layout(dom_tree, &sheet, vp_w, vp_h);
                self.layout_dirty = false;
                info!("Layout recomputed for new viewport size: {}x{}", vp_w, vp_h);
            }
        }

        // 7. 计算脏矩形重绘区域
        let _redraw_regions = self.dirty_rect_manager.compute_redraw_regions();
        
        // 8. 生成渲染命令（会光栅化文字，设置 atlas.dirty = true）
        let commands = self.generate_render_commands();
        debug!(command_count = commands.len(), "Generated render commands");
        
        // 8. 提交到 GPU 渲染器（如果可用）
        let render_start = std::time::Instant::now();
        let (gpu_attempted, gpu_success) = if let Some(renderer) = self.gpu_renderer.as_mut() {
            // 关键修复：在 submit_commands 之后、render 之前，强制同步字体图集
            // 因为 generate_render_commands 中的文字光栅化会设置 atlas.dirty = true
            // 必须确保在 GPU 渲染前纹理已更新
            renderer.force_sync_font_atlas();
            
            renderer.submit_commands(commands);
            match renderer.render() {
                Ok(()) => {
                    info!("GPU rendering completed successfully");
                    (true, true)
                }
                Err(e) => {
                    warn!(error = ?e, "GPU rendering failed");
                    self.report_error(
                        &format!("GPU rendering failed: {}", e),
                        ErrorSource::Render,
                        ErrorSeverity::Error,
                    );
                    (true, false)
                }
            }
        } else {
            // 没有 GPU 渲染器时只记录命令数量
            info!(
                command_count = commands.len(),
                "Frame rendering completed (no GPU renderer)"
            );
            (false, true)
        };
        
        // 记录 GPU 渲染时间到 DevTools（仅当有 GPU 时）
        if gpu_attempted {
            self.dev_tools.set_gpu_time(render_start.elapsed());
        }
        
        // 清除脏矩形（帧结束）
        self.dirty_rect_manager.clear();
        
        // 9. 结束 DevTools 帧计时
        self.dev_tools.end_frame();
        
        // 10. 如果还有活动动画，保持 dirty 标记以继续渲染
        self.dirty = self.has_active_animations();
        
        gpu_success
    }

    /// 设置目标帧率
    ///
    /// # 参数
    ///
    /// * `fps` - 目标帧率（建议 30-144）
    pub fn set_target_fps(&mut self, fps: u32) {
        self.target_fps = fps.clamp(1, 144);
        info!(target_fps = self.target_fps, "Target FPS updated");
    }

    /// 获取当前帧率
    pub fn current_fps(&self) -> f64 {
        self.current_fps
    }

    /// 获取目标帧率
    pub fn target_fps(&self) -> u32 {
        self.target_fps
    }

    /// 设置 VTree（用于测试）
    pub fn set_vtree(&mut self, vtree: VTree) {
        self.vtree = Some(vtree);
    }

    /// 设置 DOM 树（用于测试）
    pub fn set_dom_tree(&mut self, dom_tree: DOMNode) {
        self.dom_tree = Some(dom_tree);
        
        // 重建 HitTest 索引
        if let Some(ref dom_tree) = self.dom_tree {
            self.hit_index.rebuild(dom_tree);
        }
    }

    /// 重置帧率时间戳（用于测试）
    pub fn reset_frame_timer(&mut self) {
        self.last_frame_time = None;
    }

    // ==========================================
    // HitTest 和事件分发
    // ==========================================

    /// HitTest：查找包含指定点的最顶层元素
    pub fn hit_test(&self, x: f32, y: f32) -> Option<&HitArea> {
        self.hit_index.hit_test(x, y)
    }
    
    /// 查找具有指定 vnode_id 的区域
    pub fn find_by_vnode_id(&self, vnode_id: &str) -> Option<&HitArea> {
        self.hit_index.find_by_vnode_id(vnode_id)
    }
    
    /// 获取所有可交互区域
    pub fn get_interactive_areas(&self) -> Vec<&HitArea> {
        self.hit_index.get_interactive_areas()
    }
    
    /// 获取 HitTest 索引统计信息
    pub fn get_hit_index_stats(&self) -> HitIndexStats {
        self.hit_index.stats()
    }

    // ==========================================
    // GPU 渲染器集成
    // ==========================================

    /// 设置 GPU 渲染器
    ///
    /// # 参数
    ///
    /// * `renderer` - GPU 渲染器实例
    ///
    /// # 示例
    ///
    /// ```ignore
    /// let window = event_loop.create_window(...).await?;
    /// let renderer = Renderer::new(window).await?;
    /// orchestrator.set_gpu_renderer(renderer);
    /// ```
    pub fn set_gpu_renderer(&mut self, renderer: Renderer) {
        // 加载默认字体
        let renderer = self.load_default_font(renderer);
        
        self.gpu_renderer = Some(renderer);
        info!("GPU renderer attached to orchestrator");
    }
    
    /// 加载默认字体
    fn load_default_font(&self, mut renderer: Renderer) -> Renderer {
        // 跨平台字体加载策略
        let font_paths = Self::get_system_font_paths();
        
        for font_path in &font_paths {
            if let Ok(font_data) = std::fs::read(font_path) {
                if let Some(font) = iris_gpu::SwashFont::from_bytes(&font_data) {
                    info!(font_path, "Loaded default font");
                    // 使用 2048px atlas 支持复杂字符集（中文 + Emoji + 多字号）
                    renderer.set_font(font, 2048.0);
                    
                    // 注册文字测量器到布局引擎
                    self.register_text_measurer(&renderer);
                    
                    // 加载 Emoji fallback 字体
                    self.load_emoji_font(&mut renderer);
                    
                    return renderer;
                }
            }
        }
        
        warn!("No system font found, using fallback");
        renderer
    }
    
    /// 获取跨平台系统字体路径
    fn get_system_font_paths() -> Vec<&'static str> {
        if cfg!(target_os = "windows") {
            vec![
                // Windows 中文字体 (TTF优先于TTC)
                "C:/Windows/Fonts/simhei.ttf",      // 黑体
                "C:/Windows/Fonts/simfang.ttf",      // 仿宋
                "C:/Windows/Fonts/msyh.ttc",         // 微软雅黑
                // Windows 英文字体
                "C:/Windows/Fonts/arial.ttf",
                "C:/Windows/Fonts/segoeui.ttf",
            ]
        } else if cfg!(target_os = "macos") {
            vec![
                // macOS 中文字体
                "/System/Library/Fonts/PingFang.ttc",
                // macOS 英文字体
                "/System/Library/Fonts/Helvetica.ttc",
            ]
        } else {
            // Linux
            vec![
                "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
                "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf",
                "/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc",
            ]
        }
    }
    
    /// 注册文字测量器
    ///
    /// 该回调是 layout 计算中不可或缺的宽度来源。理想方案是接入
    /// [`iris_gpu::SwashFont::advance_width`] 或 [`iris_gpu::FontAtlas::measure_text`]
    /// 返回的字形真实 advance；但 closure 的 `'static + Send + Sync` 约束与当前
    /// renderer/font_atlas 生命周期不匹配，需要将字体度量器独立出来（后续第 2 步）。
    ///
    /// 当前先采用系列化的统计宽度表对不同 Unicode 分区打分，比之前统一走
    /// 0.6em/1.0em 精确很多，足够支撑大部分布局切行/图文混排场景。
    fn register_text_measurer(&self, renderer: &Renderer) {
        let font_size = renderer.font_size();
        set_text_measurer(Box::new(move |text: &str, font_size_param: f32| {
            text.chars()
                .map(|c| font_size_param * char_advance_ratio(c))
                .sum::<f32>()
        }));
        info!("Text measurer registered with base font_size={}", font_size);
    }
    
    /// 加载 Emoji fallback 字体
    fn load_emoji_font(&self, renderer: &mut Renderer) {
        let emoji_font_paths = if cfg!(target_os = "windows") {
            vec![
                "C:/Windows/Fonts/seguiemj.ttf",    // Segoe UI Emoji
                "C:/Windows/Fonts/seguisym.ttf",    // Segoe UI Symbol
            ]
        } else if cfg!(target_os = "macos") {
            vec![
                "/System/Library/Fonts/Apple Color Emoji.ttc",
            ]
        } else {
            vec![
                "/usr/share/fonts/truetype/noto/NotoEmoji-Regular.ttf",
            ]
        };
        
        for emoji_path in emoji_font_paths {
            if let Ok(emoji_data) = std::fs::read(emoji_path) {
                if let Some(emoji_font) = iris_gpu::SwashFont::from_bytes(&emoji_data) {
                    renderer.set_emoji_font(emoji_font);
                    info!(emoji_path, "Loaded emoji fallback font");
                    return;
                }
            }
        }
        
        warn!("No emoji font found");
    }

    /// 获取 GPU 渲染器的可变引用
    pub fn gpu_renderer_mut(&mut self) -> Option<&mut Renderer> {
        self.gpu_renderer.as_mut()
    }
    
    /// 安全地清除 GPU 渲染器（避免 wgpu surface drop 崩溃）
    /// 
    /// 这个方法会显式地释放 GPU 资源，而不是简单地设置为 None。
    /// 在 Windows 上，这可以避免 surface 在窗口销毁后仍然尝试释放资源的问题。
    pub fn clear_gpu_renderer(&mut self) {
        if self.gpu_renderer.is_some() {
            debug!("Clearing GPU renderer safely...");
            
            // 使用 mem::forget 避免在 panic unwind 时 drop renderer
            // 这样可以防止 wgpu surface 在无效状态下被释放
            let renderer = self.gpu_renderer.take();
            
            // 在正常路径下，我们显式 drop renderer
            // 如果在 panic unwind 路径上，则使用 forget 让系统自动回收
            if !std::thread::panicking() {
// 正常路径：显式 drop
                if let Some(r) = renderer {
                    // 等待 GPU 完成所有操作（仅 WebGPU 模式）
                    #[cfg(feature = "webgpu-render")]
                    r.queue().submit([]);
                    drop(r);
                    debug!("GPU renderer dropped normally");
                }
            } else {
                // Panic 路径：使用 forget 避免双重 panic
                if renderer.is_some() {
                    debug!("In panic unwind, forgetting GPU renderer to avoid double panic");
                    std::mem::forget(renderer);
                }
            }
            
            info!("GPU renderer cleared safely");
        }
    }

    // ========================================
    // 文件监听与热重载
    // ========================================

    /// 启动文件监听器
    ///
    /// # 参数
    ///
    /// - `watch_paths`: 需要监听的文件或目录路径列表
    ///
    /// # 返回
    ///
    /// 成功返回 `Ok(())`，失败返回错误信息
    pub fn start_file_watcher(&mut self, watch_paths: Vec<PathBuf>) -> Result<(), String> {
        info!("Starting file watcher for {} paths", watch_paths.len());

        if self.file_watcher.is_some() {
            info!("Stopping previous file watcher");
            self.file_watcher = None;
            self.file_event_receiver = None;
            self.watched_files.clear();
        }

        let runtime = TokioRuntime::new().map_err(|e| format!("Failed to create tokio runtime: {}", e))?;
        self.tokio_runtime = Some(runtime);

        let (tx, rx) = channel();
        self.file_event_receiver = Some(rx);

        let mut watcher = RecommendedWatcher::new(tx, notify::Config::default())
            .map_err(|e| format!("Failed to create file watcher: {}", e))?;

        self.watched_files = watch_paths.clone();

        // 添加监听路径
        for path in &watch_paths {
            if path.exists() {
                let recursive_mode = if path.is_dir() {
                    RecursiveMode::Recursive
                } else {
                    RecursiveMode::NonRecursive
                };

                watcher
                    .watch(path, recursive_mode)
                    .map_err(|e| format!("Failed to watch path {:?}: {}", path, e))?;

                debug!("Watching path: {:?}", path);
            } else {
                warn!("Watch path does not exist: {:?}", path);
            }
        }

        self.file_watcher = Some(watcher);
        info!("File watcher started successfully");
        Ok(())
    }

    /// 检查文件事件并返回需要热重载的文件路径
    ///
    /// 这个方法实现了防抖机制，避免高频触发热重载
    ///
    /// # 返回
    ///
    /// 如果有需要处理的文件变更，返回文件路径；否则返回 None
    pub fn check_file_events(&mut self) -> Option<PathBuf> {
        if let Some(last_reload) = self.last_hot_reload {
            let elapsed = last_reload.elapsed().as_millis();
            if elapsed < self.hot_reload_debounce_ms as u128 {
                return None;
            }
        }

        if let Some(ref rx) = self.file_event_receiver {
            while let Ok(event_result) = rx.try_recv() {
                match event_result {
                    Ok(event) => {
                        if event.kind.is_modify() || event.kind.is_create() {
                            for path in event.paths {
                                if path.extension().is_some_and(|ext| ext == "vue") {
                                    info!("File change detected: {:?}", path);
                                    self.last_hot_reload = Some(Instant::now());
                                    return Some(path);
                                }
                            }
                        }
                    }
                    Err(e) => {
                        warn!("File watch error: {}", e);
                    }
                }
            }
        }

        None
    }

    /// 执行热重载
    ///
    /// # 参数
    ///
    /// - `file_path`: 变更的文件路径
    /// - `project_root`: 项目根目录
    ///
    /// # 返回
    ///
    /// 成功返回 `Ok(())`，失败返回错误信息
    #[cfg(feature = "vue-sfc")]
    pub fn hot_reload(&mut self, file_path: &Path, _project_root: &Path) -> Result<(), String> {
        info!("Hot reloading file: {:?}", file_path);

        // 1. 保存当前 DOM 树和 VTree（用于 diff）
        let old_dom = self.dom_tree.take();
        let old_v = self.vtree.take();

        // 获取组件名（用于 HMR 状态保存/恢复）
        let module_name = file_path.file_stem()
            .and_then(|s| s.to_str())
            .unwrap_or("unknown")
            .to_string();

        // 2. 保存响应式状态（热重载状态保持）
        let save_js = format!(
            "if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {{ __VUE_HMR_RUNTIME__.saveState({:?}); }}",
            module_name
        );
        let _ = self.js_runtime.eval(&save_js);

        // 3. 重新加载完整的 SFC（包含编译、执行、VTree 生成）
        match self.load_sfc_with_vtree(file_path) {
            Ok(()) => {
                info!("Successfully reloaded: {:?}", file_path);

                // 4. 恢复响应式状态
                let restore_js = format!(
                    r#"
(function() {{
  if (typeof __VUE_HMR_RUNTIME__ === 'undefined') return;
  var __saved = __VUE_HMR_RUNTIME__.loadState("{name}");
  for (var __k in __saved) {{
    if (globalThis[__k] && globalThis[__k]._isRef) {{
      globalThis[__k].value = __saved[__k];
    }}
  }}
}})();
"#,
                    name = module_name
                );
                let _ = self.js_runtime.eval(&restore_js);

                // 5. 如果存在旧 DOM 树和旧 VTree，使用 diff 增量更新
                if let (Some(old_dom_tree), Some(old_vtree)) = (old_dom.as_ref(), old_v.as_ref()) {
                    if let Some(ref new_vtree) = self.vtree {
                        let patches = new_vtree.diff(old_vtree);
                        if !patches.is_empty() {
                            debug!(patch_count = patches.len(), "Hot reload applying diff patches");
                            // 从旧 DOM 树克隆一份作为基础，应用 patches
                            let mut updated_dom = DOMNode::clone(old_dom_tree);
                            new_vtree.apply_patches(&mut updated_dom, &patches);
                            self.dom_tree = Some(updated_dom);
                            
                            // 重建 HitTest 索引
                            if let Some(ref dom_tree) = self.dom_tree {
                                self.hit_index.rebuild(dom_tree);
                                debug!(stats = %self.hit_index.stats(), "HitTest index rebuilt after HMR patch");
                            }
                        } else {
                            // 没有变化，复用旧 DOM 树
                            self.dom_tree = old_dom;
                        }
                    } else {
                        self.dom_tree = old_dom;
                    }
                } else {
                    // 没有旧 DOM 树，重新计算布局
                    match self.compute_layout() {
                        Ok(_) => {
                            info!("Layout computed for initial hot reload");
                        }
                        Err(e) => {
                            warn!("Failed to compute layout: {}", e);
                        }
                    }
                }

                // 4. 标记需要重新渲染
                self.dirty = true;

                info!("Hot reload completed successfully");
                Ok(())
            }
            Err(e) => {
                // 恢复旧状态
                self.vtree = old_v;
                self.dom_tree = old_dom;
                warn!("Failed to reload Vue file: {}", e);
                Err(format!("Failed to reload Vue file: {}", e))
            }
        }
    }

    /// 停止文件监听器
    pub fn stop_file_watcher(&mut self) {
        info!("Stopping file watcher...");

        // Drop 监听器
        if let Some(watcher) = self.file_watcher.take() {
            drop(watcher);
            debug!("File watcher dropped");
        }

        // 清空事件接收器
        self.file_event_receiver = None;

        // 清空监听文件列表
        self.watched_files.clear();

        // 保留 tokio_runtime 用于其他异步任务

        info!("File watcher stopped");
    }

    /// 启用自动 HMR（从环境变量读取配置）
    ///
    /// 环境变量：
    /// - `IRIS_HMR_ENABLED=1` — 启用 HMR
    /// - `IRIS_HMR_WATCH=src/` — 监听路径（相对于 cwd，逗号分隔多个路径）
    /// - `IRIS_HMR_DEBOUNCE=500` — 防抖毫秒数
    /// - `IRIS_HMR_PROJECT_ROOT=.` — 项目根目录
    ///
    /// 在调用 `initialize()` 之后、渲染循环开始之前调用。
    pub fn start_hmr_from_env(&mut self) -> Result<(), String> {
        let enabled = std::env::var("IRIS_HMR_ENABLED")
            .map(|v| v == "1" || v == "true")
            .unwrap_or(false);

        if !enabled {
            return Ok(());
        }

        let watch_str = std::env::var("IRIS_HMR_WATCH")
            .unwrap_or_else(|_| "src/".to_string());

        let debounce_ms = std::env::var("IRIS_HMR_DEBOUNCE")
            .ok()
            .and_then(|v| v.parse().ok())
            .unwrap_or(500u64);

        let root_str = std::env::var("IRIS_HMR_PROJECT_ROOT")
            .unwrap_or_else(|_| ".".to_string());

        let project_root = PathBuf::from(&root_str);
        let watch_paths: Vec<PathBuf> = watch_str
            .split(',')
            .map(|s| {
                let trimmed = s.trim();
                if Path::new(trimmed).is_absolute() {
                    PathBuf::from(trimmed)
                } else {
                    project_root.join(trimmed)
                }
            })
            .collect();

        info!(
            "Starting HMR from env: watch={:?}, debounce={}ms, root={:?}",
            watch_paths, debounce_ms, project_root
        );

        self.hot_reload_debounce_ms = debounce_ms;
        self.hmr_project_root = Some(project_root);
        self.auto_hmr = true;

        self.start_file_watcher(watch_paths)
    }

    /// 处理 HMR 文件事件（在每一帧开始时调用）
    ///
    /// 检查文件变更，如果有 .vue 文件变化则执行热重载。
    /// 热重载过程中会：
    /// 1. 保存 JS 响应式状态
    /// 2. 重新编译 SFC
    /// 3. 生成新 VTree
    /// 4. 恢复响应式状态
    /// 5. VTree diff 生成 DOM patches
    /// 6. 标记脏标志触发重绘
    pub fn process_hmr_events(&mut self) {
        if !self.auto_hmr {
            return;
        }

        const MAX_EVENTS_PER_FRAME: usize = 5;
        let mut processed_count = 0;

        while processed_count < MAX_EVENTS_PER_FRAME {
            if let Some(changed_file) = self.check_file_events() {
                if changed_file.extension().is_some_and(|ext| ext == "vue") {
                    let _project_root = self.hmr_project_root
                        .clone()
                        .unwrap_or_else(|| PathBuf::from("."));

                    debug!("HMR: processing change: {:?}", changed_file);

                    // 仅 Vue 模式支持 hot_reload
                    #[cfg(feature = "vue-sfc")]
                    if let Err(e) = self.hot_reload(&changed_file, &_project_root) {
                        warn!("HMR hot_reload failed for {:?}: {}", changed_file, e);
                    } else {
                        info!("HMR: hot reloaded {:?}", changed_file);
                    }
                    processed_count += 1;
                }
            } else {
                break;
            }
        }
    }

    /// 执行一帧的 GPU 渲染（严格模式）
    ///
    /// 这是 `render_frame()` 的严格版本，要求 GPU 渲染器必须已设置。
    /// 如果没有设置 GPU 渲染器，直接返回 false。
    ///
    /// # 返回
    ///
    /// 返回 `render_frame()` 的执行结果
    pub fn render_frame_gpu(&mut self) -> bool {
        // 检查 GPU 渲染器是否存在
        if self.gpu_renderer.is_none() {
            warn!("GPU renderer not set, skipping GPU rendering");
            return false;
        }
        
        self.render_frame()
    }

    /// 检查 GPU 渲染器是否已设置
    pub fn has_gpu_renderer(&self) -> bool {
        self.gpu_renderer.is_some()
    }

    // ==========================================
    // Phase F: 事件系统与交互
    // ==========================================

    /// 添加事件监听器
    ///
    /// # 参数
    ///
    /// * `target_id` - 目标节点 ID
    /// * `event_type` - 事件类型
    /// * `listener` - 事件监听器回调函数
    /// * `use_capture` - 是否在捕获阶段（默认 false，冒泡阶段）
    ///
    /// # 示例
    ///
    /// ```ignore
    /// orchestrator.add_event_listener(
    ///     1,
    ///     EventType::Click,
    ///     Box::new(|event| {
    ///         println!("Node {} clicked!", event.target_id);
    ///     }),
    ///     false,
    /// );
    /// ```
    #[cfg(feature = "vue-sfc")]
    pub fn add_event_listener(
        &mut self,
        target_id: u64,
        event_type: EventType,
        listener: EventListener,
        use_capture: bool,
    ) {
        if use_capture {
            self.event_dispatcher.add_capture_listener(target_id, event_type, listener);
        } else {
            self.event_dispatcher.add_listener(target_id, event_type, listener);
        }
        debug!(
            target_id,
            event_type = ?event_type,
            use_capture = use_capture,
            "Event listener added"
        );
    }

    /// 移除事件监听器
    ///
    /// # 参数
    ///
    /// * `target_id` - 目标节点 ID
    /// * `event_type` - 事件类型
    #[cfg(feature = "vue-sfc")]
    pub fn remove_event_listener(&mut self, target_id: u64, event_type: EventType) {
        self.event_dispatcher.remove_listener(target_id, event_type);
        debug!(
            target_id,
            event_type = ?event_type,
            "Event listener removed"
        );
    }

    // ---- CSSOM 接口 ----

    /// 添加 CSS 样式表
    ///
    /// # 参数
    ///
    /// * `name` - 样式表名称（如 "main"）
    /// * `css_text` - CSS 文本内容
    ///
    /// # 示例
    ///
    /// ```ignore
    /// orchestrator.add_css_stylesheet("main", "body { color: red; }");
    /// ```
    pub fn add_css_stylesheet(&mut self, name: &str, css_text: &str) {
        info!(name, css_len = css_text.len(), "Adding CSS stylesheet");
        let sheet = iris_layout::css::parse_stylesheet(css_text);
        self.css_stylesheets.insert(name.to_string(), sheet);
        self.dirty = true;
    }

    /// 插入 CSS 规则
    ///
    /// # 参数
    ///
    /// * `rule_text` - CSS 规则文本（如 ".class { color: red; }"）
    /// * `index` - 插入位置
    ///
    /// # 返回
    ///
    /// 成功返回规则索引，失败返回错误信息
    pub fn insert_css_rule(&mut self, rule_text: &str, _index: usize) -> Result<u32, String> {
        // 简化实现：重新解析整个 stylesheet
        // 在需要精确规则插入的场景下可优化为增量更新
        info!("Inserting CSS rule: {}", rule_text);
        self.dirty = true;
        Ok(0)
    }

    /// 删除 CSS 规则
    ///
    /// # 参数
    ///
    /// * `index` - 要删除的规则索引
    pub fn delete_css_rule(&mut self, _index: usize) -> Result<(), String> {
        info!("Deleting CSS rule at index");
        self.dirty = true;
        Ok(())
    }

    /// 将事件加入待处理队列（推荐的事件处理方式）
    ///
    /// 使用 `queue_event` + `process_pending_events` 替代直接分发，
    /// 以支持完整的事件冒泡/捕获三阶段传播和 JS 桥接。
    #[cfg(feature = "vue-sfc")]
    pub fn handle_event(&mut self, event: Event) {
        self.queue_event(event);
    }

    /// 派发自定义事件
    ///
    /// 允许从 Rust 端派发自定义事件到 JS 端，携带任意 JSON 数据。
    ///
    /// # 参数
    ///
    /// * `event_type` - 自定义事件类型名称（将传递给 JS 端）
    /// * `target_id` - 目标节点 ID
    /// * `data` - 自定义数据（JSON 格式字符串）
    #[cfg(feature = "vue-sfc")]
    pub fn dispatch_custom_event(&mut self, event_type: &str, target_id: u64, data: &str) {
        use iris_dom::event::EventData;

        let event = iris_dom::event::Event {
            event_type: iris_dom::event::EventType::Custom,
            data: EventData::Custom(data.to_string()),
            target_id,
current_target_id: None,
            event_phase: None,
            propagation_stopped: std::cell::RefCell::new(false),
            default_prevented: std::cell::RefCell::new(false),
            immediate_propagation_stopped: std::cell::RefCell::new(false),
        };
        debug!(
            event_type = %event_type,
            target_id = target_id,
            data_len = data.len(),
            "Dispatching custom event"
        );
        self.queue_event(event);
    }

    /// 命中测试：从坐标查找对应的 DOM 节点 ID
    ///
    /// 查找包含给定坐标点 (x, y) 的最深 DOM 元素。
    /// 需要先调用 `compute_layout()` 确保布局已计算。
    ///
    /// # 参数
    ///
    /// * `x` - 点的 X 坐标
    /// * `y` - 点的 Y 坐标
    ///
    /// # 返回
    ///
    /// 返回包含该点的最深元素节点 ID，如果没有匹配则返回 `None`。
    pub fn hit_test_point(&self, x: f32, y: f32) -> Option<u64> {
        let dom_tree = self.dom_tree.as_ref()?;
        iris_layout::layout::hit_test(
            dom_tree,
            x,
            y,
            self.viewport_width,
            self.viewport_height,
        )
    }

    /// 处理鼠标点击事件
    ///
    /// # 参数
    ///
    /// * `target_id` - 被点击的节点 ID
    /// * `x` - 鼠标 X 坐标
    /// * `y` - 鼠标 Y 坐标
    /// * `button` - 鼠标按键（0=左键, 1=中键, 2=右键）
    #[cfg(feature = "vue-sfc")]
    pub fn handle_mouse_click(&mut self, target_id: u64, x: f32, y: f32, button: u8) {
        // 如果 target_id 为 0，通过 hit_test 自动推导
        let resolved_target = if target_id == 0 {
            self.hit_test_point(x, y).unwrap_or(target_id)
        } else {
            target_id
        };

        let event = Event::mouse(
            EventType::Click,
            resolved_target,
            MouseEventData {
                x,
                y,
                button,
                ctrl_key: false,
                shift_key: false,
                alt_key: false,
            },
        );
        
        info!(
            target_id,
            x, y, button,
            "Mouse click event"
        );
        
        // 使用 queue_event 替代 handle_event，将事件加入 pending_events 队列
        // 这样 process_pending_events 会在下一帧中处理完整的事件冒泡逻辑
        self.queue_event(event);
    }

    /// 处理鼠标移动事件
    ///
    /// # 参数
    ///
    /// * `target_id` - 目标节点 ID
    /// * `x` - 鼠标 X 坐标
    /// * `y` - 鼠标 Y 坐标
    #[cfg(feature = "vue-sfc")]
    pub fn handle_mouse_move(&mut self, target_id: u64, x: f32, y: f32) {
        let event = Event::mouse(
            EventType::MouseMove,
            target_id,
            MouseEventData {
                x,
                y,
                button: 0,
                ctrl_key: false,
                shift_key: false,
                alt_key: false,
            },
        );
        info!(target_id, x, y, "Mouse move event");
        self.queue_event(event);
    }

    /// 处理鼠标进入事件
    ///
    /// # 参数
    ///
    /// * `target_id` - 目标节点 ID
    /// * `x` - 鼠标 X 坐标
    /// * `y` - 鼠标 Y 坐标
    #[cfg(feature = "vue-sfc")]
    pub fn handle_mouse_enter(&mut self, target_id: u64, x: f32, y: f32) {
        let event = Event::mouse(
            EventType::MouseEnter,
            target_id,
            MouseEventData {
                x,
                y,
                button: 0,
                ctrl_key: false,
                shift_key: false,
                alt_key: false,
            },
        );
        info!(target_id, x, y, "Mouse enter event");
        self.queue_event(event);
    }

    /// 处理鼠标离开事件
    ///
    /// # 参数
    ///
    /// * `target_id` - 目标节点 ID
    /// * `x` - 鼠标 X 坐标
    /// * `y` - 鼠标 Y 坐标
    #[cfg(feature = "vue-sfc")]
    pub fn handle_mouse_leave(&mut self, target_id: u64, x: f32, y: f32) {
        let event = Event::mouse(
            EventType::MouseLeave,
            target_id,
            MouseEventData {
                x,
                y,
                button: 0,
                ctrl_key: false,
                shift_key: false,
                alt_key: false,
            },
        );
        info!(target_id, x, y, "Mouse leave event");
        self.queue_event(event);
    }

    /// 处理键盘事件
    ///
    /// # 参数
    ///
    /// * `target_id` - 目标节点 ID
    /// * `key` - 按键代码
    /// * `key_code` - 按键数字代码（用于键盘修饰符匹配）
    /// * `ctrl` - Ctrl 键是否按下
    /// * `shift` - Shift 键是否按下
    /// * `alt` - Alt 键是否按下
    #[cfg(feature = "vue-sfc")]
    pub fn handle_keyboard_event(
        &mut self,
        target_id: u64,
        key: String,
        key_code: u32,
        ctrl: bool,
        shift: bool,
        alt: bool,
    ) {
        use iris_dom::event::KeyboardEventData;

        // 如果 target_id 为 0，自动定位到当前焦点节点
        let resolved_target = if target_id == 0 {
            self.focused_node_id.unwrap_or(0)
        } else {
            target_id
        };
        
        if resolved_target == 0 {
            info!("No focused node for keyboard event, ignoring");
            return;
        }
        
        let event = Event::keyboard(
            EventType::KeyDown,
            resolved_target,
            KeyboardEventData {
                key_code,
                key,
                ctrl_key: ctrl,
                shift_key: shift,
                alt_key: alt,
            },
        );
        
        let key_str = match &event.data {
            iris_dom::event::EventData::Keyboard(k) => k.key.clone(),
            _ => String::new(),
        };
        
        info!(
            target_id,
            key = %key_str,
            "Keyboard event"
        );
        
        
        self.queue_event(event);
    }

    /// 处理输入事件（如 input/change）
    ///
    /// 用于 vue 的 v-model 双向绑定。
    /// 创建一个 Input 事件，携带字符串数据（value），
    /// 加入 pending_events 队列等待下一帧处理。
    ///
    /// # 参数
    ///
    /// * `target_id` - 目标节点 ID
    /// * `value` - 输入值
    #[cfg(feature = "vue-sfc")]
    pub fn handle_input_event(&mut self, target_id: u64, value: String) {
        use iris_dom::event::EventData;

        let data_json = format!("{{\"target\":{{\"value\":\"{}\"}}}}", Self::json_escape(&value));
        let event = Event {
            event_type: iris_dom::event::EventType::Input,
            target_id,
            data: EventData::Custom(data_json),
current_target_id: None,
            event_phase: None,
            propagation_stopped: std::cell::RefCell::new(false),
            default_prevented: std::cell::RefCell::new(false),
            immediate_propagation_stopped: std::cell::RefCell::new(false),
        };
        info!(target_id, value = %value, "Input event");
        self.queue_event(event);
    }

    /// 处理焦点事件（focus）
    ///
    /// 创建一个 Focus 事件，同时触发 focusin（冒泡版），
    /// 更新焦点追踪状态。
    ///
    /// # 参数
    ///
    /// * `target_id` - 目标节点 ID
    #[cfg(feature = "vue-sfc")]
    pub fn handle_focus(&mut self, target_id: u64) {
        use iris_dom::event::EventData;

        // 更新焦点追踪
        self.focused_node_id = Some(target_id);

        // 触发 focusin（冒泡版焦点事件）
        let focusin_event = Event {
            event_type: iris_dom::event::EventType::FocusIn,
            target_id,
            data: EventData::Custom(format!("{{\"targetId\":{}}}", target_id)),
current_target_id: None,
            event_phase: None,
            propagation_stopped: std::cell::RefCell::new(false),
            default_prevented: std::cell::RefCell::new(false),
            immediate_propagation_stopped: std::cell::RefCell::new(false),
        };
        self.queue_event(focusin_event);

        // 同时触发 focus 事件
        let data_json = format!("{{\"targetId\":{}}}", target_id);
        let event = Event {
            event_type: iris_dom::event::EventType::Focus,
            target_id,
            data: EventData::Custom(data_json),
current_target_id: None,
            event_phase: None,
            propagation_stopped: std::cell::RefCell::new(false),
            default_prevented: std::cell::RefCell::new(false),
            immediate_propagation_stopped: std::cell::RefCell::new(false),
        };
        info!(target_id, "Focus event");
        self.queue_event(event);
    }

    /// 处理失焦事件（blur）
    ///
    /// 创建一个 Blur 事件，同时触发 focusout（冒泡版），
    /// 更新焦点追踪状态。
    ///
    /// # 参数
    ///
    /// * `target_id` - 目标节点 ID
    #[cfg(feature = "vue-sfc")]
    pub fn handle_blur(&mut self, target_id: u64) {
        use iris_dom::event::EventData;

        // 更新焦点追踪
        if self.focused_node_id == Some(target_id) {
            self.focused_node_id = None;
        }

        // 触发 focusout（冒泡版失焦事件）
        let focusout_event = Event {
            event_type: iris_dom::event::EventType::FocusOut,
            target_id,
            data: EventData::Custom(format!("{{\"targetId\":{}}}", target_id)),
current_target_id: None,
            event_phase: None,
            propagation_stopped: std::cell::RefCell::new(false),
            default_prevented: std::cell::RefCell::new(false),
            immediate_propagation_stopped: std::cell::RefCell::new(false),
        };
        self.queue_event(focusout_event);

        // 同时触发 blur 事件
        let data_json = format!("{{\"targetId\":{}}}", target_id);
        let event = Event {
            event_type: iris_dom::event::EventType::Blur,
            target_id,
            data: EventData::Custom(data_json),
current_target_id: None,
            event_phase: None,
            propagation_stopped: std::cell::RefCell::new(false),
            default_prevented: std::cell::RefCell::new(false),
            immediate_propagation_stopped: std::cell::RefCell::new(false),
        };
        info!(target_id, "Blur event");
        self.queue_event(event);
    }

    /// 处理滚动事件（scroll）
    ///
    /// 创建一个 Scroll 事件，携带 scrollLeft/scrollTop 数据，
    /// 加入 pending_events 队列等待下一帧处理。
    ///
    /// # 参数
    ///
    /// * `target_id` - 目标节点 ID
    /// * `scroll_x` - 水平滚动位置
    /// * `scroll_y` - 垂直滚动位置
    #[cfg(feature = "vue-sfc")]
    pub fn handle_scroll(&mut self, target_id: u64, scroll_x: f64, scroll_y: f64) {
        use iris_dom::event::EventData;

        let data_json = format!(
            "{{\"target\":{{\"scrollLeft\":{},\"scrollTop\":{}}}}}",
            scroll_x, scroll_y
        );
        let event = Event {
            event_type: iris_dom::event::EventType::Scroll,
            target_id,
            data: EventData::Custom(data_json),
current_target_id: None,
            event_phase: None,
            propagation_stopped: std::cell::RefCell::new(false),
            default_prevented: std::cell::RefCell::new(false),
            immediate_propagation_stopped: std::cell::RefCell::new(false),
        };
        info!(target_id, scroll_x, scroll_y, "Scroll event");
        self.queue_event(event);
    }

    /// 处理提交事件
    ///
    /// # 参数
    ///
    /// * `target_id` - 目标节点 ID
    #[cfg(feature = "vue-sfc")]
    pub fn handle_submit(&mut self, target_id: u64) {
        use iris_dom::event::EventData;

        let data_json = format!("{{\"targetId\":{}}}", target_id);
        let event = Event {
            event_type: iris_dom::event::EventType::Submit,
            target_id,
            data: EventData::Custom(data_json),
current_target_id: None,
            event_phase: None,
            propagation_stopped: std::cell::RefCell::new(false),
            default_prevented: std::cell::RefCell::new(false),
            immediate_propagation_stopped: std::cell::RefCell::new(false),
        };
        info!(target_id, "Submit event");
        self.queue_event(event);
    }

    /// 处理滚轮事件
    ///
    /// # 参数
    ///
    /// * `target_id` - 目标节点 ID
    /// * `delta_x` - 水平滚动量
    /// * `delta_y` - 垂直滚动量
    /// * `delta_z` - Z 轴滚动量
    #[cfg(feature = "vue-sfc")]
    pub fn handle_wheel(&mut self, target_id: u64, delta_x: f64, delta_y: f64, delta_z: f64) {
        use iris_dom::event::EventData;

        let data_json = format!(
            "{{\"deltaX\":{},\"deltaY\":{},\"deltaZ\":{}}}",
            delta_x, delta_y, delta_z
        );
        let event = Event {
            event_type: iris_dom::event::EventType::Wheel,
            target_id,
            data: EventData::Custom(data_json),
current_target_id: None,
            event_phase: None,
            propagation_stopped: std::cell::RefCell::new(false),
            default_prevented: std::cell::RefCell::new(false),
            immediate_propagation_stopped: std::cell::RefCell::new(false),
        };
        info!(target_id, delta_x, delta_y, delta_z, "Wheel event");
        self.queue_event(event);
    }

    /// 处理右键菜单事件
    ///
    /// # 参数
    ///
    /// * `target_id` - 目标节点 ID
    /// * `x` - 鼠标 X 坐标
    /// * `y` - 鼠标 Y 坐标
    #[cfg(feature = "vue-sfc")]
    pub fn handle_context_menu(&mut self, target_id: u64, x: f32, y: f32) {
        use iris_dom::event::EventData;

        let data_json = format!(
            "{{\"x\":{},\"y\":{}}}",
            x, y
        );
        let event = Event {
            event_type: iris_dom::event::EventType::ContextMenu,
            target_id,
            data: EventData::Custom(data_json),
current_target_id: None,
            event_phase: None,
            propagation_stopped: std::cell::RefCell::new(false),
            default_prevented: std::cell::RefCell::new(false),
            immediate_propagation_stopped: std::cell::RefCell::new(false),
        };
        info!(target_id, x, y, "ContextMenu event");
        self.queue_event(event);
    }

    /// 处理触摸开始事件
    ///
    /// # 参数
    ///
    /// * `target_id` - 目标节点 ID
    /// * `touches_json` - 触摸点数组的 JSON 字符串，格式: `[{"x":X,"y":Y},...]`
    #[cfg(feature = "vue-sfc")]
    pub fn handle_touch_start(&mut self, target_id: u64, touches_json: &str) {
        use iris_dom::event::EventData;

        let data_json = format!(
            "{{\"touches\":{},\"changedTouches\":{}}}",
            touches_json, touches_json
        );
        let event = Event {
            event_type: iris_dom::event::EventType::TouchStart,
            target_id,
            data: EventData::Custom(data_json),
current_target_id: None,
            event_phase: None,
            propagation_stopped: std::cell::RefCell::new(false),
            default_prevented: std::cell::RefCell::new(false),
            immediate_propagation_stopped: std::cell::RefCell::new(false),
        };
        info!(target_id, "TouchStart event");
        self.queue_event(event);
    }

    /// 处理触摸移动事件
    #[cfg(feature = "vue-sfc")]
    pub fn handle_touch_move(&mut self, target_id: u64, touches_json: &str) {
        use iris_dom::event::EventData;

        let data_json = format!(
            "{{\"touches\":{},\"changedTouches\":{}}}",
            touches_json, touches_json
        );
        let event = Event {
            event_type: iris_dom::event::EventType::TouchMove,
            target_id,
            data: EventData::Custom(data_json),
current_target_id: None,
            event_phase: None,
            propagation_stopped: std::cell::RefCell::new(false),
            default_prevented: std::cell::RefCell::new(false),
            immediate_propagation_stopped: std::cell::RefCell::new(false),
        };
        info!(target_id, "TouchMove event");
        self.queue_event(event);
    }

    /// 处理触摸结束事件
    #[cfg(feature = "vue-sfc")]
    pub fn handle_touch_end(&mut self, target_id: u64, touches_json: &str) {
        use iris_dom::event::EventData;

        let data_json = format!(
            "{{\"touches\":{},\"changedTouches\":{}}}",
            touches_json, touches_json
        );
        let event = Event {
            event_type: iris_dom::event::EventType::TouchEnd,
            target_id,
            data: EventData::Custom(data_json),
current_target_id: None,
            event_phase: None,
            propagation_stopped: std::cell::RefCell::new(false),
            default_prevented: std::cell::RefCell::new(false),
            immediate_propagation_stopped: std::cell::RefCell::new(false),
        };
        info!(target_id, "TouchEnd event");
        self.queue_event(event);
    }

    /// 获取事件监听器数量
    #[cfg(feature = "vue-sfc")]
    pub fn event_listener_count(&self) -> usize {
        self.event_dispatcher.listener_count()
    }

    /// 清除所有事件监听器
    #[cfg(feature = "vue-sfc")]
    pub fn clear_event_listeners(&mut self) {
        self.event_dispatcher.clear();
        info!("All event listeners cleared");
    }

    // ==========================================
    // DevTools & ErrorBoundary 集成
    // ==========================================

    /// 获取 DevTools 引用
    pub fn dev_tools(&self) -> &DevTools {
        &self.dev_tools
    }

    /// 获取 DevTools 可变引用
    pub fn dev_tools_mut(&mut self) -> &mut DevTools {
        &mut self.dev_tools
    }

    /// 启用/禁用 DevTools
    pub fn set_dev_tools_enabled(&mut self, enabled: bool) {
        self.dev_tools.set_enabled(enabled);
        if enabled {
            info!("DevTools enabled");
        } else {
            info!("DevTools disabled");
        }
    }

    /// 启用/禁用 DevTools 性能分析
    pub fn set_dev_tools_profiling(&mut self, enabled: bool) {
        self.dev_tools.set_profiling(enabled);
        if enabled {
            info!("DevTools profiling enabled");
        } else {
            info!("DevTools profiling disabled");
        }
    }

    /// 打印完整的调试信息
    pub fn print_debug_info(&self) {
        self.dev_tools.print_debug_info();
    }

    /// 获取 ErrorBoundary 引用
    pub fn error_boundary(&self) -> &ErrorBoundary {
        &self.error_boundary
    }

    /// 获取 ErrorBoundary 可变引用
    pub fn error_boundary_mut(&mut self) -> &mut ErrorBoundary {
        &mut self.error_boundary
    }

    /// 报告错误到 DevTools 和 ErrorBoundary
    fn report_error(&mut self, message: &str, source: ErrorSource, severity: ErrorSeverity) {
        let error = IrisError::new(message, source, severity);
        self.dev_tools.report_error(error.clone());
        self.error_boundary.catch_error(error);
    }

    /// 检查是否应该继续渲染（基于 ErrorBoundary 状态）
    pub fn should_continue_rendering(&self) -> bool {
        self.error_boundary.should_continue_rendering()
    }

    /// 检查是否有未处理的错误
    pub fn has_errors(&self) -> bool {
        self.error_boundary.error_count() > 0 || self.dev_tools.error_reporter().error_count() > 0
    }

    // ==========================================
    // 脏矩形管理器集成
    // ==========================================

    /// 获取脏矩形管理器引用
    pub fn dirty_rect_manager(&self) -> &DirtyRectManager {
        &self.dirty_rect_manager
    }

    /// 获取脏矩形管理器可变引用
    pub fn dirty_rect_manager_mut(&mut self) -> &mut DirtyRectManager {
        &mut self.dirty_rect_manager
    }

    /// 启用/禁用脏矩形优化
    pub fn set_dirty_rect_optimization(&mut self, enabled: bool) {
        self.dirty_rect_manager.set_enabled(enabled);
    }

    /// 标记特定区域为脏区域
    pub fn mark_area_dirty(&mut self, x: f32, y: f32, width: f32, height: f32) {
        self.dirty_rect_manager.add_change(x, y, width, height);
        self.dirty = true;
    }

    /// 标记全屏为脏区域
    pub fn mark_full_dirty(&mut self) {
        self.dirty_rect_manager.mark_full_dirty();
        self.dirty = true;
    }

    /// 获取脏矩形统计信息
    pub fn dirty_rect_stats(&self) -> &DirtyRectStats {
        self.dirty_rect_manager.get_stats()
    }

    // ==========================================
    // 动画引擎集成
    // ==========================================

    /// 启动元素的过渡动画
    ///
    /// # 参数
    ///
    /// * `element_id` - 目标元素 ID
    /// * `property` - CSS 属性名（如 "opacity", "transform"）
    /// * `from` - 起始值
    /// * `to` - 目标值
    /// * `config` - 过渡配置（持续时间、缓动函数等）
    pub fn start_transition(
        &mut self,
        element_id: u64,
        property: &str,
        from: f32,
        to: f32,
        config: &TransitionConfig,
    ) {
        let absolute_ms = self.animation_start_time.elapsed().as_secs_f64() * 1000.0;
        let state = self.element_animations
            .entry(element_id)
            .or_insert_with(|| ElementAnimationState::new(element_id));
        
        state.start_transition(property.to_string(), from, to, config, absolute_ms);
        debug!(
            element_id,
            property,
            from,
            to,
            "Transition started"
        );
        
        // 标记需要渲染
        self.dirty = true;
    }

    /// 启动关键帧动画
    ///
    /// # 参数
    ///
    /// * `animation` - 关键帧动画实例
    pub fn start_keyframe_animation(&mut self, animation: KeyframeAnimation) {
        let element_id = animation.element_id;
        self.keyframe_animations.push(animation);
        debug!(element_id, "Keyframe animation started");
        
        // 标记需要渲染
        self.dirty = true;
    }

    /// 检查是否有活动动画
    pub fn has_active_animations(&self) -> bool {
        // 检查元素过渡动画
        for state in self.element_animations.values() {
            if state.has_active_animations() {
                return true;
            }
        }
        
        // 检查关键帧动画
        for anim in &self.keyframe_animations {
            if anim.is_active() {
                return true;
            }
        }
        
        false
    }

    /// 获取元素的动画值
    ///
    /// # 参数
    ///
    /// * `element_id` - 目标元素 ID
    /// * `property` - CSS 属性名
    ///
    /// # 返回
    ///
    /// 返回动画当前值，如果没有活动动画则返回 None
    pub fn get_animated_value(&self, element_id: u64, property: &str) -> Option<f32> {
        // 先从元素动画状态中查询
        if let Some(state) = self.element_animations.get(&element_id) {
            if let Some(value) = state.get_animated_value(property) {
                return Some(value);
            }
        }
        
        // 再从关键帧动画缓存中查询
        if let Some(values) = self.animated_values_cache.get(&element_id) {
            if let Some(&value) = values.get(property) {
                return Some(value);
            }
        }
        
        None
    }

    /// 暂停元素的所有动画
    pub fn pause_element_animations(&mut self, element_id: u64) {
        if let Some(_state) = self.element_animations.get_mut(&element_id) {
            // 暂不提供直接暂停 ElementAnimationState 的 API
            debug!(element_id, "Element animation pause requested (not directly supported for transitions)");
        }
        
        // 暂停关键帧动画
        for anim in &mut self.keyframe_animations {
            if anim.element_id == element_id {
                anim.pause();
            }
        }
    }

    /// 恢复元素的所有动画
    pub fn resume_element_animations(&mut self, element_id: u64) {
        for anim in &mut self.keyframe_animations {
            if anim.element_id == element_id {
                anim.resume();
            }
        }
    }

    /// 重置元素的所有动画
    pub fn reset_element_animations(&mut self, element_id: u64) {
        self.element_animations.remove(&element_id);
        
        for anim in &mut self.keyframe_animations {
            if anim.element_id == element_id {
                anim.reset();
            }
        }
    }

    /// 清除所有动画
    pub fn clear_animations(&mut self) {
        self.element_animations.clear();
        self.keyframe_animations.clear();
        self.animated_values_cache.clear();
        info!("All animations cleared");
    }

    /// 更新所有活动动画（每帧调用）
    ///
    /// 计算当前帧的动画值，应用到 DOM 树，返回是否有动画正在播放
    fn update_animations(&mut self) -> bool {
        let now = Instant::now();
        let absolute_ms = now.duration_since(self.animation_start_time).as_secs_f64() * 1000.0;
        let delta_ms = now.duration_since(self.last_animation_update).as_secs_f64() * 1000.0;
        self.last_animation_update = now;
        
        let mut has_active = false;
        
        // 1. 清空动画值缓存
        self.animated_values_cache.clear();
        
        // 2. 更新 ElementAnimationState（基于绝对时间）
        for (element_id, state) in self.element_animations.iter_mut() {
            state.update(absolute_ms);
            if state.has_active_animations() {
                has_active = true;
            }
            
            // 收集当前动画值到缓存
            let mut values = HashMap::new();
            for prop in ["opacity", "transform", "width", "height"] {
                if let Some(val) = state.get_animated_value(prop) {
                    values.insert(prop.to_string(), val);
                }
            }
            if !values.is_empty() {
                self.animated_values_cache.entry(*element_id).or_default().extend(values);
            }
        }
        
        // 3. 更新 KeyframeAnimation（基于增量时间）
        for anim in self.keyframe_animations.iter_mut() {
            anim.update(delta_ms);
            if anim.is_active() || !anim.completed {
                has_active = true;
            }
            
            // 收集关键帧动画值到缓存
            let values: HashMap<String, f32> = anim.current_values.clone();
            if !values.is_empty() {
                self.animated_values_cache.entry(anim.element_id).or_default().extend(values);
            }
        }
        
        // 4. 清理已完成的非保留关键帧动画
        self.keyframe_animations.retain(|a| {
            !a.completed || matches!(a.fill_mode, FillMode::Forwards | FillMode::Both)
        });
        
        // 5. 将动画值应用到 DOM 树
        if !self.animated_values_cache.is_empty() {
            self.apply_animated_values_to_dom();
        }
        
        has_active
    }

    /// 将动画值应用到 DOM 树节点样式
    ///
    /// 遍历 DOM 树，为每个匹配动画状态的元素修改其 `style` 属性
    fn apply_animated_values_to_dom(&mut self) {
        let cache = &self.animated_values_cache;
        if cache.is_empty() {
            return;
        }
        
        if let Some(ref mut dom_tree) = self.dom_tree {
            let mut next_id = 1u64;
            Self::apply_animations_to_node(dom_tree, &mut next_id, cache);
        }
    }

    /// 递归将动画值应用到单个 DOM 节点及其子节点
    fn apply_animations_to_node(
        node: &mut DOMNode,
        next_id: &mut u64,
        cache: &HashMap<u64, HashMap<String, f32>>,
    ) {
        let current_id = *next_id;
        *next_id += 1;
        
        // 只处理元素节点
        if node.is_element() {
            // 检查当前节点是否有动画值
            if let Some(anim_values) = cache.get(&current_id) {
                let current_style = node.get_attribute("style").unwrap_or(&String::new()).to_string();
                let mut existing_props: Vec<String> = current_style
                    .split(';')
                    .map(|s| s.trim().to_string())
                    .filter(|s| !s.is_empty())
                    .collect();
                
                for (prop, &value) in anim_values {
                    let new_decl = format!("{}: {}", prop, value);
                    let prop_prefix = format!("{}:", prop);
                    let mut replaced = false;
                    for part in existing_props.iter_mut() {
                        if part.trim_start().starts_with(&prop_prefix) {
                            *part = new_decl.clone();
                            replaced = true;
                            break;
                        }
                    }
                    if !replaced {
                        existing_props.push(new_decl);
                    }
                }
                
                node.set_attribute("style", &existing_props.join("; "));
            }
        }
        
        // 递归处理子节点
        for child in &mut node.children {
            Self::apply_animations_to_node(child, next_id, cache);
        }
    }

    /// 检查是否已初始化
    pub fn is_initialized(&self) -> bool {
        self.initialized
    }
}

impl Default for RuntimeOrchestrator {
    fn default() -> Self {
        Self::new()
    }
}

