"""luiFunction component and HTTP creation mixin."""

import json
import threading
import time
import urllib.error
import urllib.request
from pathlib import Path

import panda3d.core as p3d
from panda3d.core import CardMaker, NodePath
from imgui_bundle import imgui, imgui_ctx

from ui.LUI.lui_shared import (
    LUICheckbox,
    LUIFrame,
    LUIHorizontalLayout,
    LUIButton,
    LUILabel,
    LUIInputField,
    LUISlider,
    LUISprite,
    LUIObject,
    LUIProgressbar,
    LUISelectbox,
    LUIScrollableRegion,
    LUITabbedFrame,
    LUIVerticalLayout,
)


class LUIFunctionComponentsMixin:
    def create_canvas(manager, name=None):
        """创建一个可视化的 UI 面板作为画布"""
        manager.canvas_counter += 1
        canvas_name = name or f"{manager.canvas_counter}"
        
        # 获取窗口尺寸
        win_width = 800
        win_height = 600
        if hasattr(manager.world, 'win'):
            win_width = manager.world.win.getXSize()
            win_height = manager.world.win.getYSize()

        # 计算场景窗口区域（排除Hierarchy面板）
        left_offset = 0
        if hasattr(manager.world, 'hierarchy_size'):
            left_offset = manager.world.hierarchy_size.x
            
        target_width = win_width - left_offset
        target_height = win_height
        
        canvas_panel = LUIObject(parent=manager.overlay_root, x=left_offset, y=0)
        
        # 显式设置尺寸
        canvas_panel.width = target_width
        canvas_panel.height = target_height
        canvas_panel.solid = True # 接收事件
        
        # 创建背景 Sprite
        bg = LUISprite(canvas_panel, "blank", "skin")
        bg.width = target_width
        bg.height = target_height
        bg.color = (0.5, 0.5, 0.5, 1.0)  # 半透明灰色背景，可见但不遮挡ImGui
        # Canvas背景在LUI内部的底层
        if hasattr(bg, 'set_sort'):
            bg.set_sort(-1)  # LUI内部的底层
            
        # Canvas面板使用默认层级（继承自LUI Region的sort=5）
        # 不需要额外设置sort，会自动继承LUI Region的层级
        canvas_panel.solid = True  # 接收事件，用于Canvas交互
        
        # 创建Canvas的NodePath节点用于层级树显示
        canvas_node = NodePath(canvas_name)
        canvas_node.reparent_to(manager.world.render)
        
        # 存储Canvas数据
        canvas_data = {
            'name': canvas_name,
            'node': canvas_node,
            'panel': canvas_panel,
            'visible': True,
            'background': bg,
            'fill_mode': True,  # 默认开启填充模式
            'margins': {
                'left': 240,
                'right': 480,  # 默认右侧面板宽度
                'top': 89,
                'bottom': 220  # 默认底部面板高度
            }
        }
        
        # 应用初始几何计算 (调用 manager 的方法)
        # 注意：这里需要 manager 是 public 的或者我们访问 protected 方法
        if hasattr(manager, '_update_canvas_geometry'):
            manager._update_canvas_geometry(canvas_data)
        
        # 添加面板标题
        title_text = f"Canvas: {canvas_name}"
        title = LUILabel(text=title_text, font_size=16)
        title.set_parent(canvas_panel)
        title.set_pos(10, 10) # 内部 padding
        if hasattr(title, 'set_color'):
            title.set_color((0.8, 0.8, 0.8, 1.0))
        
        # 存储标题引用以便后续修改
        canvas_data['title_label'] = title
        
        # 启用Canvas拖动
        if hasattr(manager, '_make_canvas_draggable'):
            manager._make_canvas_draggable(canvas_panel)
        
        manager.canvases.append(canvas_data)
        manager.current_canvas_index = len(manager.canvases) - 1
        manager.switch_canvas(manager.current_canvas_index)
        
        # 调试输出：确认Canvas层级
        print(f"✓ Created Canvas: {canvas_name}")
        print(f"  Canvas panel sort: {getattr(canvas_panel, 'sort', 'N/A')}")
        print(f"  Background sprite sort: {getattr(bg, 'sort', 'N/A')}")
        
        if hasattr(manager.world, 'updateSceneTree'):
            manager.world.updateSceneTree()
        return canvas_data

    def create_button(manager, text="Button", x=100, y=100, parent=None):
        """Create a LUI Button"""
        if not manager.lui_enabled: return None
        
        # 如果没有指定parent，使用当前Canvas的panel作为parent
        if parent is None and manager.current_canvas_index >= 0:
            parent = manager.canvases[manager.current_canvas_index]['panel']
        elif parent is None:
            parent = manager.overlay_root
            
        btn = LUIButton(parent=parent, text=text, x=x, y=y)

        # Ensure size is initialized so selection bounds match the actual button
        default_w = 100
        default_h = 30
        try:
            if not hasattr(btn, 'width') or btn.width is None or btn.width <= 0:
                btn.width = default_w
            if not hasattr(btn, 'height') or btn.height is None or btn.height <= 0:
                btn.height = default_h
        except Exception:
            pass

        width = getattr(btn, 'width', default_w) or default_w
        height = getattr(btn, 'height', default_h) or default_h

        
        # 设置组件层级，在Canvas背景之上
        if hasattr(btn, 'set_sort'):
            btn.set_sort(1)  # 在Canvas背景之上
        
        comp_data = {
            'type': 'Button',
            'object': btn,
            'widget': btn,
            'text': text,
            'left': x,
            'top': y,
            'width': float(width),
            'height': float(height),
            'canvas_index': manager.current_canvas_index,
            'name': f"Button_{len(manager.components)}",
            'color': (1.0, 1.0, 1.0, 1.0),
            'sort': 1
        }
        
        # 设置拖拽功能
        comp_index = len(manager.components)
        if hasattr(manager, '_setup_component_drag'):
            manager._setup_component_drag(comp_data, comp_index)
        
        if hasattr(manager, '_add_to_scene_tree'):
             manager._add_to_scene_tree(comp_data)
        
        manager.components.append(comp_data)
        return btn

    def create_label(manager,text="Text", x=100, y=100, font_size=14, parent=None):
            """Create a LUI Text"""
            if not manager.lui_enabled: return None
            
            # 如果没有指定parent，使用当前Canvas的panel作为parent
            if parent is None and manager.current_canvas_index >= 0:
                parent = manager.canvases[manager.current_canvas_index]['panel']
            elif parent is None:
                parent = manager.overlay_root
                
            lbl = LUILabel(parent=parent, text=text, x=x, y=y, solid=True, font_size=font_size)
            
            # 设置组件层级，在Canvas背景之上
            if hasattr(lbl, 'set_sort'):
                lbl.set_sort(1)  # 在Canvas背景之上
            
            comp_data = {
                'type': 'Text',
                'object': lbl,
                'text': text,
                'left': x,
                'top': y,
                'width': 80,
                'height': 20,
                'canvas_index': manager.current_canvas_index,
                'name': f"Text_{len(manager.components)}",
                'color': (1, 1, 1, 1),
                'font_size': font_size,
                'sort': 1
            }
            
            # 设置拖拽功能
            comp_index = len(manager.components)
            manager._setup_component_drag(comp_data, comp_index)
            
            # 添加到层级树
            manager._add_to_scene_tree(comp_data)
            
            manager.components.append(comp_data)
            return lbl

    def create_input_field(manager,text="", x=100, y=100, width=200, parent=None):
            """Create a LUI InputField"""
            if not manager.lui_enabled: return None
            
            # 如果没有指定parent，使用当前Canvas的panel作为parent
            if parent is None and manager.current_canvas_index >= 0:
                parent = manager.canvases[manager.current_canvas_index]['panel']
            elif parent is None:
                parent = manager.overlay_root
                
            inf = LUIInputField(parent=parent, value=text, x=x, y=y, width=width)
            
            comp_data = {
                'type': 'InputField',
                'object': inf,
                'text': text,
                'left': x,
                'top': y,
                'width': width,
                'height': 24,
                'canvas_index': manager.current_canvas_index,
                'name': f"InputField_{len(manager.components)}",
                'value': text,
                'placeholder': "输入文本...",
                'sort': 1
            }
            
            # 设置拖拽功能
            comp_index = len(manager.components)
            manager._setup_component_drag(comp_data, comp_index)
            
            # 添加到层级树
            manager._add_to_scene_tree(comp_data)
            
            manager.components.append(comp_data)
            return inf

    def create_slider(manager,x=100, y=100, width=200, parent=None):
        """Create a LUI Slider"""
        if not manager.lui_enabled: return None
        
        # 如果没有指定parent，使用当前Canvas的panel作为parent
        if parent is None and manager.current_canvas_index >= 0:
            parent = manager.canvases[manager.current_canvas_index]['panel']
        elif parent is None:
            parent = manager.overlay_root
            
        sld = LUISlider(parent=parent, x=x, y=y, width=width)
        if hasattr(sld, 'set_height'):
            sld.set_height(16)
        if hasattr(sld, 'height'):
            sld.height = 16
        
        comp_data = {
            'type': 'Slider',
            'object': sld,
            'left': x,
            'top': y,
            'width': width,
            'height': 16,
            'canvas_index': manager.current_canvas_index,
            'name': f"Slider_{len(manager.components)}",
            'min_value': 0.0,
            'max_value': 100.0,
            'value': 50.0,
            'sort': 1
        }
        
        # 设置拖拽功能
        comp_index = len(manager.components)
        manager._setup_component_drag(comp_data, comp_index)
        
        # 添加到层级树
        manager._add_to_scene_tree(comp_data)
        
        manager.components.append(comp_data)
        return sld

    def create_frame(manager,x=100, y=100, width=300, height=200, parent=None):
        """Create a LUI Frame"""
        if not manager.lui_enabled: return None
        
        # 如果没有指定parent，使用当前Canvas的panel作为parent
        if parent is None and manager.current_canvas_index >= 0:
            parent = manager.canvases[manager.current_canvas_index]['panel']
        elif parent is None:
            parent = manager.overlay_root
            
        frm = LUIFrame(parent=parent, x=x, y=y, width=width, height=height)
        
        comp_data = {
            'type': 'Frame',
            'object': frm,
            'left': x,
            'top': y,
            'width': width,
            'height': height,
            'canvas_index': manager.current_canvas_index,
            'name': f"Frame_{len(manager.components)}",
            'color': (0.7, 0.7, 0.7, 0.8),
            'sort': 1
        }
        
        # 设置拖拽功能
        comp_index = len(manager.components)
        manager._setup_component_drag(comp_data, comp_index)
        
        # 添加到层级树
        manager._add_to_scene_tree(comp_data)
        
        manager.components.append(comp_data)
        return frm

    def create_vertical_layout(manager, x=100, y=100, width=300, height=200, spacing=0.0, parent=None):
        """Create a LUI Vertical Layout"""
        if not manager.lui_enabled: return None

        if parent is None and manager.current_canvas_index >= 0:
            parent = manager.canvases[manager.current_canvas_index]['panel']
        elif parent is None:
            parent = manager.overlay_root

        container = LUIObject(parent=parent, x=x, y=y)
        if hasattr(container, 'width'):
            container.width = width
        if hasattr(container, 'height'):
            container.height = height
        if hasattr(container, 'solid'):
            container.solid = True

        layout = LUIVerticalLayout(parent=container, spacing=spacing)

        padding_left = 0.0
        padding_right = 0.0
        padding_top = 0.0
        padding_bottom = 0.0

        inner_w = max(1.0, float(width) - (padding_left + padding_right))
        inner_h = max(1.0, float(height) - (padding_top + padding_bottom))

        if hasattr(layout, 'left'):
            layout.left = padding_left
        if hasattr(layout, 'top'):
            layout.top = padding_top
        if hasattr(layout, 'width'):
            layout.width = inner_w
        if hasattr(layout, 'height'):
            layout.height = inner_h

        comp_data = {
            'type': 'VerticalLayout',
            'object': container,
            'layout_obj': layout,
            'left': x,
            'top': y,
            'width': width,
            'height': height,
            'layout_spacing': spacing,
            'layout_padding_left': padding_left,
            'layout_padding_right': padding_right,
            'layout_padding_top': padding_top,
            'layout_padding_bottom': padding_bottom,
            'layout_align': 'start',
            'layout_wrap': True,
            'layout_line_spacing': 0.0,
            'canvas_index': manager.current_canvas_index,
            'name': f"VerticalLayout_{len(manager.components)}",
            'sort': 1,
            'draggable': True
        }

        comp_index = len(manager.components)
        if hasattr(manager, '_setup_component_drag'):
            manager._setup_component_drag(comp_data, comp_index)

        if hasattr(manager, '_add_to_scene_tree'):
            manager._add_to_scene_tree(comp_data)

        manager.components.append(comp_data)
        return container

    def create_horizontal_layout(manager, x=100, y=100, width=300, height=200, spacing=0.0, parent=None):
        """Create a LUI Horizontal Layout"""
        if not manager.lui_enabled: return None

        if parent is None and manager.current_canvas_index >= 0:
            parent = manager.canvases[manager.current_canvas_index]['panel']
        elif parent is None:
            parent = manager.overlay_root

        container = LUIObject(parent=parent, x=x, y=y)
        if hasattr(container, 'width'):
            container.width = width
        if hasattr(container, 'height'):
            container.height = height
        if hasattr(container, 'solid'):
            container.solid = True

        layout = LUIHorizontalLayout(parent=container, spacing=spacing)

        padding_left = 0.0
        padding_right = 0.0
        padding_top = 0.0
        padding_bottom = 0.0

        inner_w = max(1.0, float(width) - (padding_left + padding_right))
        inner_h = max(1.0, float(height) - (padding_top + padding_bottom))

        if hasattr(layout, 'left'):
            layout.left = padding_left
        if hasattr(layout, 'top'):
            layout.top = padding_top
        if hasattr(layout, 'width'):
            layout.width = inner_w
        if hasattr(layout, 'height'):
            layout.height = inner_h

        comp_data = {
            'type': 'HorizontalLayout',
            'object': container,
            'layout_obj': layout,
            'left': x,
            'top': y,
            'width': width,
            'height': height,
            'layout_spacing': spacing,
            'layout_padding_left': padding_left,
            'layout_padding_right': padding_right,
            'layout_padding_top': padding_top,
            'layout_padding_bottom': padding_bottom,
            'layout_align': 'start',
            'layout_wrap': True,
            'layout_line_spacing': 0.0,
            'canvas_index': manager.current_canvas_index,
            'name': f"HorizontalLayout_{len(manager.components)}",
            'sort': 1,
            'draggable': True
        }

        comp_index = len(manager.components)
        if hasattr(manager, '_setup_component_drag'):
            manager._setup_component_drag(comp_data, comp_index)

        if hasattr(manager, '_add_to_scene_tree'):
            manager._add_to_scene_tree(comp_data)

        manager.components.append(comp_data)
        return container

    def create_checkbox(manager, label="Checkbox", x=100, y=100, parent=None):
        """Create a LUI Checkbox"""
        if not manager.lui_enabled: return None
        
        # 如果没有指定parent，使用当前Canvas的panel作为parent
        if parent is None and manager.current_canvas_index >= 0:
            parent = manager.canvases[manager.current_canvas_index]['panel']
        elif parent is None:
            parent = manager.overlay_root
            
        chk = LUICheckbox(parent=parent, label=label, x=x, y=y)
        
        comp_data = {
            'type': 'Checkbox',
            'object': chk,
            'text': label,
            'left': x,
            'top': y,
            'width': 120,
            'height': 20,
            'canvas_index': manager.current_canvas_index,
            'name': f"Checkbox_{len(manager.components)}",
            'checked': False,
            'sort': 1
        }
        
        # 设置拖拽功能
        comp_index = len(manager.components)
        manager._setup_component_drag(comp_data, comp_index)
        
        # 添加到层级树
        manager._add_to_scene_tree(comp_data)
        
        manager.components.append(comp_data)
        return chk

    def create_plane(manager, x=100, y=100, width=100, height=100, color=(1,1,1,1), parent=None):
        """Create a LUI Plane (using Sprite with blank texture)"""
        if not manager.lui_enabled: return None
        
        # 如果没有指定parent，使用当前Canvas的panel作为parent
        if parent is None and manager.current_canvas_index >= 0:
            parent = manager.canvases[manager.current_canvas_index]['panel']
        elif parent is None:
            parent = manager.overlay_root
            
        # 创建LUIObject容器
        obj = LUIObject(parent=parent, x=x, y=y)
        obj.width = width
        obj.height = height
        obj.solid = True  # 重要：设置为solid才能接收鼠标事件
        
        # 设置组件层级，在Canvas背景之上 (Plane)
        if hasattr(obj, 'set_sort'):
            obj.set_sort(1)  # 在Canvas背景之上
        
        # 创建Sprite作为平面背景
        spr = LUISprite(obj, "blank", "skin")
        spr.width = width
        spr.height = height
        spr.color = color
        spr.left = 0
        spr.top = 0
        
        comp_data = {
            'type': 'Plane',
            'object': obj,
            'sprite': spr,
            'left': x,
            'top': y,
            'width': width,
            'height': height,
            'canvas_index': manager.current_canvas_index,
            'name': f"Plane_{len(manager.components)}",
            'color': color,
            'sort': 1
        }
        
        # 设置拖拽功能
        comp_index = len(manager.components)
        manager._setup_component_drag(comp_data, comp_index)
        
        # 添加到层级树
        manager._add_to_scene_tree(comp_data)
        
        manager.components.append(comp_data)
        return obj

    def create_image(manager, texture_path="blank", x=100, y=100, width=100, height=100, parent=None):
        """Create a LUI Image"""
        if not manager.lui_enabled: return None
        
        # 如果没有指定parent，使用当前Canvas的panel作为parent
        if parent is None and manager.current_canvas_index >= 0:
            parent = manager.canvases[manager.current_canvas_index]['panel']
        elif parent is None:
            parent = manager.overlay_root
            
        # 创建LUIObject容器
        obj = LUIObject(parent=parent, x=x, y=y)
        obj.width = width
        obj.height = height
        obj.solid = True  # 重要：设置为solid才能接收鼠标事件
        
        # 设置组件层级，在Canvas背景之上 (Image)
        if hasattr(obj, 'set_sort'):
            obj.set_sort(1)  # 在Canvas背景之上
        
        # 加载纹理 (使用皮肤中的'blank'或外部路径)
        # 注意: LUISprite通常使用图集图像名称或纹理
        # 对于外部图像，可能需要加载纹理并使用不同的LUI元素
        # 或将其注册到图集中。LUISprite(parent, image, atlas)
        
        # 为了简单起见，我们使用默认皮肤sprite，它有'blank'
        img_name = "blank" 
        spr = LUISprite(obj, img_name, "skin")
        spr.width = width
        spr.height = height
        spr.left = 0
        spr.top = 0
        
        # 设置默认图像颜色（浅灰色，表示这是一个图像占位符）
        spr.color = (1.0, 1.0, 1.0, 1.0)
        
        comp_data = {
            'type': 'Image',
            'object': obj,
            'sprite': spr,
            'left': x,
            'top': y,
            'width': width,
            'height': height,
            'canvas_index': manager.current_canvas_index,
            'name': f"Image_{len(manager.components)}",
            'texture_path': texture_path,
            'color': (1.0, 1.0, 1.0, 1.0),
            'sort': 1
        }
        
        # 设置拖拽功能
        comp_index = len(manager.components)
        manager._setup_component_drag(comp_data, comp_index)
        
        # 添加到层级树
        manager._add_to_scene_tree(comp_data)
        
        manager.components.append(comp_data)
        return obj

    def create_video(manager, video_path="", x=100, y=100, width=320, height=240, parent=None):
        """Create a LUI Video Player component"""
        if not manager.lui_enabled: return None
        
        # 如果没有指定parent，使用当前Canvas的panel作为parent
        if parent is None and manager.current_canvas_index >= 0:
            parent = manager.canvases[manager.current_canvas_index]['panel']
        elif parent is None:
            parent = manager.overlay_root
            
        # 1. 创建容器对象
        obj = LUIObject(parent=parent, x=x, y=y)
        obj.width = width
        obj.height = height
        obj.solid = True
        
        # 设置层级
        if hasattr(obj, 'set_sort'):
            obj.set_sort(1)
            
        # 2. 准备视频纹理
        video_texture = None
        if video_path:
            try:
                from panda3d.core import Filename, MovieTexture, MovieVideo, loadPrcFileData
                # Trim whitespace which could cause "file not found" errors
                video_path = video_path.strip()
                
                # Allow network protocols
                loadPrcFileData("", "ffmpeg-protocol-whitelist http,https,tcp,tls,file")
                
                if "://" in video_path:
                    # 尝试更稳定的加载序列
                    try:
                        video_src = MovieVideo.get(Filename(video_path))
                        video_texture = MovieTexture("RemoteVideo")
                        if not video_texture.load(video_src):
                            video_texture = manager.world.loader.loadTexture(video_path)
                    except:
                        video_texture = manager.world.loader.loadTexture(video_path)
                else:
                    video_texture = manager.world.loader.loadTexture(Filename.from_os_specific(video_path))
                
                if video_texture:
                    print(f"✓ 视频加载成功: {video_path}")
                    # 尝试同步视频尺寸比例
                    orig_w = video_texture.getOrigFileXSize()
                    orig_h = video_texture.getOrigFileYSize()
                    if orig_w > 0 and orig_h > 0:
                        ratio = orig_w / orig_h
                        # 保持宽度，调整高度
                        new_height = width / ratio
                        obj.height = new_height
                        height = new_height # Update local var
            except Exception as e:
                print(f"⚠ 加载视频失败: {e}")




        # 2.1 ???????????????????????????????????????

        audio_sound = None
        audio_path = ""
        audio_from_video = False
        if video_path and "://" not in video_path:
            try:
                audio_path = video_path
                audio_sound = manager.world.loader.loadSfx(p3d.Filename.from_os_specific(video_path))
                if audio_sound:
                    audio_from_video = True
                    if hasattr(audio_sound, 'setLoop'):
                        audio_sound.setLoop(True)
                    if hasattr(audio_sound, 'setVolume'):
                        audio_sound.setVolume(1.0)
            except Exception:
                audio_sound = None
                audio_path = ""

        # 3. 创建Sprite
        if video_texture:
            # 直接使用纹理创建，不使用Atlas
            spr = LUISprite(obj, video_texture)
            spr.color = (1, 1, 1, 1) # Video needs white to show original colors
        else:
            # 使用默认黑色背景
            spr = LUISprite(obj, "blank", "skin")
            spr.color = (0.0, 0.0, 0.0, 1.0) 

        spr.width = width
        spr.height = height

        if video_texture:
            obj.video_texture = video_texture # Prevent GC
            
            # Ensure full UVs
            if hasattr(spr, 'set_uv_range'):
                spr.set_uv_range(0, 0, 1, 1)
            
            # 如果支持，自动播放
            if hasattr(video_texture, 'play'):
                # Stop first to reset state, critical for some video formats
                if hasattr(video_texture, 'stop'):
                     video_texture.stop()
                video_texture.play()
            if hasattr(video_texture, 'setLoop'):
                video_texture.setLoop(True)
        if audio_sound:
            try:
                if hasattr(audio_sound, 'stop'):
                    audio_sound.stop()
                if hasattr(audio_sound, 'play'):
                    audio_sound.play()
            except Exception:
                pass
        
        # 4. 创建简单的控制栏 (可选，这里先做个占位符)
        # TODO: Play/Pause controls
        
        comp_data = {
            'type': 'Video',
            'object': obj,
            'sprite': spr,
            'left': x,
            'top': y,
            'width': width,
            'height': height,
            'canvas_index': manager.current_canvas_index,
            'name': f"Video_{len(manager.components)}",
            'video_path': video_path,
            'texture': video_texture,
            'audio': audio_sound,
            'audio_path': audio_path,
            'audio_from_video': audio_from_video,
            'volume': 1.0,
            'is_playing': True,
            'loop': True,
            'sort': 1
        }
        
        # 设置拖拽功能
        comp_index = len(manager.components)
        manager._setup_component_drag(comp_data, comp_index)
        
        # 添加到层级树
        manager._add_to_scene_tree(comp_data)
        
        manager.components.append(comp_data)
        return obj

    def create_http_text(manager, x=100, y=100, width=320, height=120, url="https://api.open-meteo.com/v1/forecast?latitude=39.9042&longitude=116.4074&current=temperature_2m,apparent_temperature,relative_humidity_2m,wind_speed_10m&timezone=Asia%2FShanghai", parent=None):
        """Create a HTTP text component that fetches data from URL and renders it."""
        if not manager.lui_enabled:
            return None

        if parent is None and manager.current_canvas_index >= 0:
            parent = manager.canvases[manager.current_canvas_index]['panel']
        elif parent is None:
            parent = manager.overlay_root

        obj = LUIObject(parent=parent, x=x, y=y)
        obj.width = width
        obj.height = height
        obj.solid = True

        if hasattr(obj, 'set_sort'):
            obj.set_sort(1)

        # Panel background
        spr = LUISprite(obj, "blank", "skin")
        spr.width = width
        spr.height = height
        spr.left = 0
        spr.top = 0
        spr.color = (0.08, 0.14, 0.20, 0.92)

        # Text content
        text_label = LUILabel(
            parent=obj,
            text="HTTP组件\n点击“立即请求”获取数据",
            x=8,
            y=8,
            font_size=14,
            wordwrap=True
        )
        text_label.color = (0.92, 0.95, 1.0, 1.0)

        comp_data = {
            'type': 'HttpText',
            'object': obj,
            'sprite': spr,
            'text_label': text_label,
            'text': "HTTP组件\n点击“立即请求”获取数据",
            'left': x,
            'top': y,
            'width': width,
            'height': height,
            'canvas_index': manager.current_canvas_index,
            'name': f"HttpText_{len(manager.components)}",
            'sort': 1,
            'color': (0.08, 0.14, 0.20, 0.92),
            'text_color': (0.92, 0.95, 1.0, 1.0),
            'error_color': (1.0, 0.40, 0.40, 1.0),
            'text_padding': 8.0,
            # HTTP settings
            'http_url': url,
            'http_method': 'GET',
            'http_headers': '{}',
            'http_body': '',
            'http_timeout': 8.0,
            'http_json_path': 'current',
            'auto_refresh': True,
            'refresh_interval': 60.0,
            'max_chars': 300,
            'http_status': '未请求',
            'last_error': '',
            'last_response_raw': '',
            'last_refresh_time': 0.0,
            # Runtime flags
            '_http_inflight': False,
            '_http_pending_result': None,
        }

        manager.luiFunction.sync_http_text_layout(manager, comp_data)

        comp_index = len(manager.components)
        manager._setup_component_drag(comp_data, comp_index)
        manager._add_to_scene_tree(comp_data)
        manager.components.append(comp_data)

        # Trigger first request in background
        manager.luiFunction.trigger_http_request(manager, comp_data, force=True)
        return obj

    def sync_http_text_layout(manager, comp_data):
        """Keep HttpText internal label in sync with panel size and padding."""
        if comp_data.get('type') != 'HttpText':
            return

        label = comp_data.get('text_label')
        if label is None:
            return

        pad = float(comp_data.get('text_padding', 8.0))
        width = float(comp_data.get('width', 100.0))
        height = float(comp_data.get('height', 40.0))
        inner_w = max(1.0, width - pad * 2.0)
        inner_h = max(1.0, height - pad * 2.0)

        try:
            label.left = pad
            label.top = pad
            if hasattr(label, 'width'):
                label.width = inner_w
            if hasattr(label, 'height'):
                label.height = inner_h
        except Exception:
            pass

    def _extract_json_by_path(path_text, payload):
        """Extract value from JSON payload by a simple path: a.b[0].c"""
        if not path_text:
            return payload

        path = str(path_text).strip()
        if not path:
            return payload

        tokens = []
        current = ""
        i = 0
        while i < len(path):
            ch = path[i]
            if ch == '.':
                if current:
                    tokens.append(('key', current))
                    current = ""
                i += 1
                continue
            if ch == '[':
                if current:
                    tokens.append(('key', current))
                    current = ""
                j = path.find(']', i + 1)
                if j < 0:
                    raise ValueError(f"JSON路径非法: {path_text}")
                idx_text = path[i + 1:j].strip()
                if not idx_text:
                    raise ValueError(f"JSON路径非法: {path_text}")
                tokens.append(('index', int(idx_text)))
                i = j + 1
                continue
            current += ch
            i += 1

        if current:
            tokens.append(('key', current))

        node = payload
        for token_type, token_val in tokens:
            if token_type == 'key':
                if not isinstance(node, dict):
                    raise KeyError(f"JSON路径错误，期望对象: {token_val}")
                node = node[token_val]
            else:
                if not isinstance(node, (list, tuple)):
                    raise KeyError(f"JSON路径错误，期望数组: [{token_val}]")
                node = node[token_val]

        return node

    def _set_http_text_display(manager, comp_data, text, is_error=False):
        """Update HttpText display text and color."""
        msg = text if text is not None else ""
        comp_data['text'] = msg
        label = comp_data.get('text_label')
        if label is None:
            return

        try:
            label.text = msg
            if is_error:
                color = comp_data.get('error_color', (1.0, 0.4, 0.4, 1.0))
            else:
                color = comp_data.get('text_color', (0.92, 0.95, 1.0, 1.0))
            if hasattr(label, 'set_color'):
                label.set_color(color)
            else:
                label.color = color
        except Exception:
            pass

    def trigger_http_request(manager, comp_data, force=False):
        """Start one async HTTP request for HttpText component."""
        if comp_data.get('type') != 'HttpText':
            return False

        if comp_data.get('_http_inflight'):
            return False

        now_ts = time.time()
        if not force:
            interval = max(1.0, float(comp_data.get('refresh_interval', 60.0)))
            last_ts = float(comp_data.get('last_refresh_time', 0.0))
            if now_ts - last_ts < interval:
                return False

        url = str(comp_data.get('http_url', '')).strip()
        if not url:
            comp_data['http_status'] = "URL为空"
            comp_data['last_error'] = "URL为空"
            manager.luiFunction._set_http_text_display(manager, comp_data, "HTTP请求失败: URL为空", is_error=True)
            return False

        method = str(comp_data.get('http_method', 'GET')).upper().strip()
        if method not in ('GET', 'POST'):
            method = 'GET'
            comp_data['http_method'] = 'GET'

        timeout_sec = max(1.0, float(comp_data.get('http_timeout', 8.0)))
        headers_raw = str(comp_data.get('http_headers', '{}'))
        body_raw = str(comp_data.get('http_body', ''))
        json_path = str(comp_data.get('http_json_path', '')).strip()
        max_chars = max(32, int(comp_data.get('max_chars', 300)))

        comp_data['_http_inflight'] = True
        comp_data['http_status'] = "请求中..."

        def _worker():
            result = {
                'ok': False,
                'message': '',
                'status_code': None,
                'error': '',
                'time': time.time(),
                'raw': '',
            }
            try:
                headers = {}
                if headers_raw.strip():
                    parsed_headers = json.loads(headers_raw)
                    if not isinstance(parsed_headers, dict):
                        raise ValueError("Headers 必须是 JSON 对象")
                    headers = {str(k): str(v) for k, v in parsed_headers.items()}

                data_bytes = None
                if body_raw:
                    data_bytes = body_raw.encode('utf-8')

                request = urllib.request.Request(
                    url=url,
                    data=data_bytes,
                    headers=headers,
                    method=method
                )

                with urllib.request.urlopen(request, timeout=timeout_sec) as response:
                    status_code = getattr(response, 'status', 200)
                    raw_bytes = response.read()
                    charset = None
                    response_headers = getattr(response, 'headers', None)
                    if response_headers is not None and hasattr(response_headers, 'get_content_charset'):
                        charset = response_headers.get_content_charset()
                    if not charset:
                        charset = "utf-8"
                    raw_text = raw_bytes.decode(charset, errors='replace')

                    display_text = raw_text.strip()
                    if json_path:
                        json_payload = json.loads(raw_text)
                        extracted = manager.luiFunction._extract_json_by_path(json_path, json_payload)
                        if isinstance(extracted, (dict, list)):
                            display_text = json.dumps(extracted, ensure_ascii=False)
                        else:
                            display_text = str(extracted)

                    if len(display_text) > max_chars:
                        display_text = display_text[:max_chars] + "..."

                    result['ok'] = True
                    result['message'] = display_text
                    result['status_code'] = status_code
                    result['raw'] = raw_text
            except Exception as err:
                result['error'] = str(err)

            comp_data['_http_pending_result'] = result

        thread = threading.Thread(target=_worker, daemon=True)
        thread.start()
        return True

    def update_http_components(manager):
        """Consume async HTTP results and run auto-refresh."""
        now_ts = time.time()
        for comp_data in manager.components:
            if comp_data.get('type') != 'HttpText':
                continue

            pending = comp_data.get('_http_pending_result')
            if pending is not None:
                comp_data['_http_pending_result'] = None
                comp_data['_http_inflight'] = False
                comp_data['last_refresh_time'] = float(pending.get('time', now_ts))
                comp_data['last_response_raw'] = pending.get('raw', '')

                if pending.get('ok'):
                    status_code = pending.get('status_code')
                    stamp = time.strftime("%H:%M:%S", time.localtime(comp_data['last_refresh_time']))
                    comp_data['http_status'] = f"HTTP {status_code} @ {stamp}"
                    comp_data['last_error'] = ''
                    manager.luiFunction._set_http_text_display(
                        manager,
                        comp_data,
                        pending.get('message', ''),
                        is_error=False
                    )
                else:
                    error_msg = pending.get('error', '未知错误')
                    comp_data['last_error'] = error_msg
                    comp_data['http_status'] = "请求失败"
                    manager.luiFunction._set_http_text_display(
                        manager,
                        comp_data,
                        f"HTTP请求失败: {error_msg}",
                        is_error=True
                    )

            # Auto refresh
            if comp_data.get('auto_refresh', False) and not comp_data.get('_http_inflight'):
                interval = max(1.0, float(comp_data.get('refresh_interval', 60.0)))
                last_ts = float(comp_data.get('last_refresh_time', 0.0))
                if now_ts - last_ts >= interval:
                    manager.luiFunction.trigger_http_request(manager, comp_data, force=True)

    def create_progressbar(manager, value=50, x=100, y=100, width=200, parent=None):
        """Create a LUI Progressbar"""
        if not manager.lui_enabled: return None
        
        if parent is None and manager.current_canvas_index >= 0:
            parent = manager.canvases[manager.current_canvas_index]['panel']
        elif parent is None:
            parent = manager.overlay_root
            
        pg = LUIProgressbar(parent=parent, width=width, value=value)
        pg.left = x
        pg.top = y
        pg.solid = True # Ensure it receives input
        
        if hasattr(pg, 'set_sort'):
            pg.set_sort(1)

        comp_data = {
            'type': 'Progressbar',
            'object': pg,
            'left': x,
            'top': y,
            'width': width,
            'height': 30, # default height
            'canvas_index': manager.current_canvas_index,
            'name': f"Progressbar_{len(manager.components)}",
            'value': value,
            'sort': 1
        }
        
        comp_index = len(manager.components)
        manager._setup_component_drag(comp_data, comp_index)
        manager._add_to_scene_tree(comp_data)
        manager.components.append(comp_data)
        return pg

    def create_selectbox(manager, options=None, x=100, y=100, width=200, parent=None):
        """Create a LUI Selectbox"""
        if not manager.lui_enabled: return None
        
        if parent is None and manager.current_canvas_index >= 0:
            parent = manager.canvases[manager.current_canvas_index]['panel']
        elif parent is None:
            parent = manager.overlay_root
            
        if options is None:
            options = [(0, "Option 1"), (1, "Option 2"), (2, "Option 3")]
            
        sb = LUISelectbox(width=width, options=options, selected_option=0)
        sb.parent = parent
        sb.left = x
        sb.top = y
        sb.solid = True # Ensure it receives input
        
        if hasattr(sb, 'set_sort'):
            sb.set_sort(1)

        comp_data = {
            'type': 'Selectbox',
            'object': sb,
            'left': x,
            'top': y,
            'width': width,
            'height': 30, # default height
            'canvas_index': manager.current_canvas_index,
            'name': f"Selectbox_{len(manager.components)}",
            'options': options,
            'sort': 1
        }
        
        comp_index = len(manager.components)
        manager._setup_component_drag(comp_data, comp_index)
        manager._add_to_scene_tree(comp_data)
        manager.components.append(comp_data)
        return sb

    def create_scrollable_region(manager, x=100, y=100, width=200, height=200, parent=None):
        """Create a LUI Scrollable Region"""
        if not manager.lui_enabled: return None
        
        if parent is None and manager.current_canvas_index >= 0:
            parent = manager.canvases[manager.current_canvas_index]['panel']
        elif parent is None:
            parent = manager.overlay_root
            
        sr = LUIScrollableRegion(parent=parent, width=width, height=height)
        sr.left = x
        sr.top = y
        sr.solid = True # Ensure it receives input
        
        if hasattr(sr, 'set_sort'):
            sr.set_sort(1)

        comp_data = {
            'type': 'ScrollableRegion',
            'object': sr,
            'left': x,
            'top': y,
            'width': width,
            'height': height,
            'canvas_index': manager.current_canvas_index,
            'name': f"ScrollableRegion_{len(manager.components)}",
            'sort': 1
        }
        
        comp_index = len(manager.components)
        manager._setup_component_drag(comp_data, comp_index)
        manager._add_to_scene_tree(comp_data)
        manager.components.append(comp_data)
        return sr

    def create_tabbed_frame(manager, x=100, y=100, width=300, height=200, parent=None):
        """Create a LUI Tabbed Frame"""
        if not manager.lui_enabled: return None
        
        if parent is None and manager.current_canvas_index >= 0:
            parent = manager.canvases[manager.current_canvas_index]['panel']
        elif parent is None:
            parent = manager.overlay_root
            
        tf = LUITabbedFrame(parent=parent, width=width, height=height)
        tf.left = x
        tf.top = y
        tf.solid = True # Ensure it receives input
        
        # Add default tabs
        f1 = LUIFrame(width=width, height=height)
        tf.add("Tab 1", f1)
        f2 = LUIFrame(width=width, height=height)
        tf.add("Tab 2", f2)
        
        if hasattr(tf, 'set_sort'):
            tf.set_sort(1)

        comp_data = {
            'type': 'TabbedFrame',
            'object': tf,
            'left': x,
            'top': y,
            'width': width,
            'height': height,
            'canvas_index': manager.current_canvas_index,
            'name': f"TabbedFrame_{len(manager.components)}",
            'sort': 1
        }
        
        comp_index = len(manager.components)
        manager._setup_component_drag(comp_data, comp_index)
        manager._add_to_scene_tree(comp_data)
        manager.components.append(comp_data)
        return tf
