use eframe::egui;

use crate::{
    connection::{ConnectionManager, ConnectionState},
    recording::Recorder,
    style::{
        self, ACCENT_BLUE, ACCENT_GREEN, ACCENT_ORANGE, ACCENT_RED, METRICS, ONE_DARK_PRO,
        accent_text, dim_text, group_frame, layout, panel_frame, tag_button,
    },
    utils::serial_enum,
};

pub struct FloatingPanelState {
    pub visible: bool,
    default_pos: egui::Pos2,
    tag_pos: egui::Pos2,
    center_anim: f32,
    center_anim_target: bool,
    center_anim_last_time: Option<f64>,
}

pub struct ConfigPanelState {
    pub mode: SerialMode,
    pub port: String,
    pub baud_rate: u32,
    pub data_bits: u8,
    pub stop_bits: u8,
    pub parity: Parity,
    pub timeout_ms: u32,
    pub module_addr: u8,
    pub connected: bool,
    pub auto_reconnect: bool,
    pub manual_tx: String,
    pub model_path: String,
}

pub struct ConnectPanelState {
    pub mode: SerialMode,
    pub port: Vec<String>,
    pub selected_port: String,
    pub duration: u8,
    pub manual: bool,
    pub rows: u8,
    pub cols: u8,
    pub connection: bool,
}

#[derive(Clone, Copy, PartialEq, Eq)]
pub enum SerialMode {
    Finger,
    Hand,
}

#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Parity {
    None,
    Odd,
    Even,
}

pub enum IconButtonIcon<'a> {
    Font(&'a str),
    Png(egui::ImageSource<'a>),
}

impl FloatingPanelState {
    pub fn new(default_pos: [f32; 2], tag_pos: [f32; 2]) -> Self {
        Self {
            visible: true,
            default_pos: egui::pos2(default_pos[0], default_pos[1]),
            tag_pos: egui::pos2(tag_pos[0], tag_pos[1]),
            center_anim: 1.0,
            center_anim_target: true,
            center_anim_last_time: None,
        }
    }
}

impl Default for ConfigPanelState {
    fn default() -> Self {
        Self {
            mode: SerialMode::Finger,
            port: "COM3".to_owned(),
            baud_rate: 115_200,
            data_bits: 8,
            stop_bits: 1,
            parity: Parity::None,
            timeout_ms: 1000,
            module_addr: 1,
            connected: false,
            auto_reconnect: true,
            manual_tx: "01 03 00 00 00 02".to_owned(),
            model_path: "model/default.eskin".to_owned(),
        }
    }
}

impl Default for ConnectPanelState {
    fn default() -> Self {
        let port = serial_enum().unwrap_or_default();
        let selected_port = port.first().cloned().unwrap_or_default();
        Self {
            mode: SerialMode::Finger,
            port,
            selected_port,
            duration: 10,
            manual: false,
            rows: 12,
            cols: 7,
            connection: false,
        }
    }
}

pub fn draw_scene_panel(ctx: &egui::Context, panel: &mut FloatingPanelState) {
    draw_floating_panel(ctx, panel, "场景", "scene_panel", |ui| {
        ui.horizontal(|ui| {
            ui.colored_label(dim_text(), "视图");
            let _ = ui.selectable_label(true, "簇");
            let _ = ui.selectable_label(false, "三角形");
        });
        ui.separator();
        group_frame().show(ui, |ui| {
            ui.label("模型 / 材质 / 灯光");
            ui.label("目标任务   64");
            ui.label("缓存命中 100.0%");
        });
    });
}

pub fn draw_connect_panel(
    ctx: &egui::Context,
    panel: &mut FloatingPanelState,
    config: &mut ConnectPanelState,
    connection: &ConnectionManager,
    recorder: &Recorder,
    export_path: &mut String,
) {
    let conn_state = connection.state();
    let is_connected = matches!(
        conn_state,
        ConnectionState::Connected | ConnectionState::Streaming
    );

    draw_center_floating_panel(
        ctx,
        panel,
        "connect_center_panel",
        layout::CENTER_PANEL_TOP,
        "连接",
        |ui| {
            ui.vertical(|ui| {
                // centered_mode_row(ui, &mut config.mode);
                ui.add_space(METRICS.row_gap);

                group_frame().show(ui, |ui| {
                    ui.horizontal(|ui| {
                        ui.add(
                            egui::Image::new(egui::include_image!("../static/cpu.png"))
                                .fit_to_exact_size(egui::vec2(64.0, 64.0)),
                        );
                        ui.add_space(METRICS.item_gap);

                        ui.vertical(|ui| {
                            draw_connect_port_row(ui, config);
                            ui.add_space(6.0);
                            draw_connect_matrix_row(ui, config);
                        });
                    });
                });

                ui.add_space(METRICS.row_gap);
                draw_connect_action_row(ui, conn_state, is_connected, config, connection);

                if is_connected {
                    draw_recording_toolbar(ui, recorder, export_path);
                }
            });
        },
    );
}

// fn centered_mode_row(ui: &mut egui::Ui, mode: &mut SerialMode) {
//     let button_width = 96.0;
//     let gap = METRICS.item_gap;
//     let total_width = button_width * 3.0 + gap * 2.0;
//     let left_space = ((ui.available_width() - total_width) * 0.5).max(0.0);

//     ui.horizontal(|ui| {
//         ui.add_space(left_space);
//         mode_button(ui, mode, SerialMode::Finger, "指尖模块");
//         ui.add_space(gap);
//         mode_button(ui, mode, SerialMode::Hand, "手掌模块");
//         // ui.add_space(gap);
//         // mode_button(ui, mode, SerialMode::Model, "模型");
//     });
// }

fn draw_connect_port_row(ui: &mut egui::Ui, config: &mut ConnectPanelState) {
    ui.horizontal(|ui| {
        ui.label(style::field_label("串口"));
        egui::ComboBox::from_id_salt("connect_ports")
            .width(150.0)
            .selected_text(if config.selected_port.is_empty() {
                "无可用串口".to_owned()
            } else {
                config.selected_port.clone()
            })
            .show_ui(ui, |ui| {
                for port in &config.port {
                    ui.selectable_value(&mut config.selected_port, port.clone(), port.as_str());
                }
            });

        if ui
            .add(style::icon_button(
                egui::RichText::new("⟳").color(ONE_DARK_PRO.text).size(16.0),
                METRICS.icon_button,
            ))
            .on_hover_text("刷新串口")
            .clicked()
        {
            if let Ok(ports) = serial_enum() {
                if !ports.contains(&config.selected_port) {
                    config.selected_port = ports.first().cloned().unwrap_or_default();
                }
                config.port = ports;
            }
        }

        ui.add_space(METRICS.item_gap);
        ui.label(style::field_label("频率"));
        ui.add_sized(
            egui::vec2(72.0, METRICS.field_height),
            egui::DragValue::new(&mut config.duration).range(1..=120),
        );
    });
}

fn draw_connect_matrix_row(ui: &mut egui::Ui, config: &mut ConnectPanelState) {
    ui.horizontal(|ui| {
        ui.checkbox(&mut config.manual, "手动矩阵");

        ui.add_enabled_ui(config.manual, |ui| {
            ui.add_space(METRICS.item_gap);
            ui.label(style::field_label("行"));
            ui.add_sized(
                egui::vec2(56.0, METRICS.field_height),
                egui::DragValue::new(&mut config.rows).range(1..=64),
            );
            ui.label(style::field_label("列"));
            ui.add_sized(
                egui::vec2(56.0, METRICS.field_height),
                egui::DragValue::new(&mut config.cols).range(1..=64),
            );
        });
    });
}

fn draw_connect_action_row(
    ui: &mut egui::Ui,
    conn_state: ConnectionState,
    is_connected: bool,
    config: &ConnectPanelState,
    connection: &ConnectionManager,
) {
    ui.horizontal(|ui| {
        let status_text = match conn_state {
            ConnectionState::Disconnected => "未连接",
            ConnectionState::Connecting => "连接中...",
            ConnectionState::Connected => "已连接",
            ConnectionState::Streaming => "采集中",
            ConnectionState::Error => "连接错误",
        };
        let status_color = match conn_state {
            ConnectionState::Disconnected => ONE_DARK_PRO.text_dim,
            ConnectionState::Connecting => style::status_color_warn(),
            ConnectionState::Connected => style::status_color_ok(),
            ConnectionState::Streaming => style::status_color_info(),
            ConnectionState::Error => style::status_color_error(),
        };

        ui.colored_label(status_color, status_text);
        ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
            let button = if is_connected {
                style::danger_button("断开")
            } else {
                style::primary_button("连接")
            };

            if ui.add(button).clicked() {
                if is_connected {
                    connection.disconnect();
                } else if !config.selected_port.is_empty() {
                    connection.connect(
                        &config.selected_port,
                        config.rows as u32,
                        config.cols as u32,
                    );
                }
            }
        });
    });
}

pub fn draw_config_panel(
    ctx: &egui::Context,
    panel: &mut FloatingPanelState,
    config: &mut ConfigPanelState,
) -> Option<SerialMode> {
    let mut changed_mode = None;
    draw_floating_panel(ctx, panel, "配置", "config_panel", |ui| {
        ui.set_min_width(560.0);

        if let Some(mode) = draw_mode_row(ui, config) {
            changed_mode = Some(mode);
        }

        // draw_mode_row(ui, config);
        ui.separator();
        draw_connection_row(ui, config);
        ui.add_space(8.0);
        draw_serial_grid(ui, config);
        ui.add_space(8.0);
        draw_mode_body(ui, config);
    });
    changed_mode
}

fn draw_mode_row(ui: &mut egui::Ui, config: &mut ConfigPanelState) -> Option<SerialMode> {
    let mut changed_to = None;
    ui.horizontal(|ui| {
        ui.colored_label(dim_text(), "模式");
        ui.add_space(12.0);

        if mode_button(ui, &mut config.mode, SerialMode::Finger, "指尖模块") {
            changed_to = Some(SerialMode::Finger)
        }
        if mode_button(ui, &mut config.mode, SerialMode::Hand, "手掌模块") {
            changed_to = Some(SerialMode::Hand)
        }
        // mode_button(ui, &mut config.mode, SerialMode::Model, "模型");

        ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
            ui.checkbox(&mut config.auto_reconnect, "自动");
            ui.colored_label(dim_text(), "重连");
        });
    });

    changed_to
}

fn draw_connection_row(ui: &mut egui::Ui, config: &mut ConfigPanelState) {
    ui.horizontal(|ui| {
        ui.add(
            egui::Image::new(egui::include_image!("../static/cpu.png"))
                .fit_to_exact_size(egui::vec2(72.0, 72.0)),
        );

        ui.add_space(METRICS.item_gap);

        ui.vertical(|ui| {
            ui.label(style::value_text(format!("端口    {}", config.port)));
            ui.label(style::value_text(format!("波特率  {}", config.baud_rate)));
            let status = if config.connected {
                "已连接"
            } else {
                "未连接"
            };
            let status_color = if config.connected {
                style::status_color_ok()
            } else {
                style::status_color_error()
            };
            ui.colored_label(status_color, status);
        });

        ui.add_space(22.0);

        let button_text = if config.connected { "断开" } else { "连接" };
        if ui
            .add(if config.connected {
                style::danger_button(button_text)
            } else {
                style::primary_button(button_text)
            })
            .clicked()
        {
            config.connected = !config.connected;
        }

        ui.add_space(18.0);
        ui.colored_label(
            if config.auto_reconnect {
                style::status_color_ok()
            } else {
                ONE_DARK_PRO.text_dim
            },
            if config.auto_reconnect {
                "链路保护 开"
            } else {
                "链路保护 关"
            },
        );
    });
}

fn draw_serial_grid(ui: &mut egui::Ui, config: &mut ConfigPanelState) {
    group_frame().show(ui, |ui| {
        egui::Grid::new("serial_config_grid")
            .num_columns(4)
            .spacing(egui::vec2(14.0, 7.0))
            .striped(true)
            .show(ui, |ui| {
                ui.label(style::field_label("端口"));
                ui.add_sized(
                    egui::vec2(110.0, METRICS.field_height),
                    egui::TextEdit::singleline(&mut config.port),
                );

                ui.label(style::field_label("波特率"));
                baud_combo(ui, config);
                ui.end_row();

                ui.label(style::field_label("数据位"));
                ui.add_sized(
                    egui::vec2(70.0, METRICS.field_height),
                    egui::DragValue::new(&mut config.data_bits).range(5..=8),
                );

                ui.label(style::field_label("校验"));
                parity_combo(ui, config);
                ui.end_row();

                ui.label(style::field_label("停止位"));
                ui.add_sized(
                    egui::vec2(70.0, METRICS.field_height),
                    egui::DragValue::new(&mut config.stop_bits).range(1..=2),
                );

                ui.label(style::field_label("超时"));
                ui.horizontal(|ui| {
                    ui.add_sized(
                        egui::vec2(84.0, METRICS.field_height),
                        egui::DragValue::new(&mut config.timeout_ms)
                            .range(50..=30_000)
                            .speed(50),
                    );
                    ui.colored_label(dim_text(), "毫秒");
                });
                ui.end_row();
            });
    });
}

fn draw_mode_body(ui: &mut egui::Ui, config: &mut ConfigPanelState) {
    group_frame().show(ui, |ui| match config.mode {
        SerialMode::Finger => {
            ui.horizontal(|ui| {
                ui.label(style::field_label("模块地址"));
                ui.add_sized(
                    egui::vec2(80.0, METRICS.field_height),
                    egui::DragValue::new(&mut config.module_addr).range(1..=247),
                );
                ui.add_space(16.0);
                if ui.add(tag_button("读取信息")).clicked() {}
                if ui.add(tag_button("探测")).clicked() {}
            });
            ui.separator();
            ui.horizontal(|ui| {
                ui.colored_label(dim_text(), "状态");
                ui.label("就绪");
                ui.colored_label(dim_text(), "接收");
                ui.label("0 字节");
                ui.colored_label(dim_text(), "发送");
                ui.label("0 字节");
            });
        }
        SerialMode::Hand => {
            ui.horizontal(|ui| {
                ui.label(style::field_label("发送"));
                ui.add_sized(
                    egui::vec2(300.0, METRICS.field_height),
                    egui::TextEdit::singleline(&mut config.manual_tx),
                );
                if ui.add(tag_button("发送")).clicked() {}
                if ui.add(tag_button("清空")).clicked() {
                    config.manual_tx.clear();
                }
            });
        } // SerialMode::Model => {
          //     ui.horizontal(|ui| {
          //         ui.label(style::field_label("模型"));
          //         ui.add_sized(
          //             egui::vec2(300.0, METRICS.field_height),
          //             egui::TextEdit::singleline(&mut config.model_path),
          //         );
          //         if ui.add(tag_button("加载")).clicked() {}
          //         if ui.add(tag_button("运行")).clicked() {}
          //     });
          // }
    });
}

pub fn icon_button<'a>(
    ui: &mut egui::Ui,
    icon: IconButtonIcon<'a>,
    tooltip: impl Into<egui::WidgetText>,
) -> egui::Response {
    icon_button_sized(ui, icon, tooltip, egui::vec2(28.0, 24.0))
}

pub fn icon_button_sized<'a>(
    ui: &mut egui::Ui,
    icon: IconButtonIcon<'a>,
    tooltip: impl Into<egui::WidgetText>,
    size: egui::Vec2,
) -> egui::Response {
    let button = match icon {
        IconButtonIcon::Font(icon) => egui::Button::new(
            egui::RichText::new(icon)
                .color(egui::Color32::WHITE)
                .size(size.y - 8.0),
        ),
        IconButtonIcon::Png(source) => egui::Button::image(
            egui::Image::new(source).fit_to_exact_size(egui::vec2(size.y - 8.0, size.y - 8.0)),
        ),
    }
    .fill(ONE_DARK_PRO.panel_strong)
    .stroke(egui::Stroke::new(1.0, ONE_DARK_PRO.border))
    .corner_radius(egui::CornerRadius::same(ONE_DARK_PRO.radius))
    .min_size(size);

    ui.add(button).on_hover_text(tooltip)
}

fn mode_button(
    ui: &mut egui::Ui,
    mode: &mut SerialMode,
    value: SerialMode,
    label: &'static str,
) -> bool {
    let clicked = ui.add(style::mode_button(label, *mode == value)).clicked();

    if clicked && *mode != value {
        *mode = value;
        true
    } else {
        false
    }
}

fn baud_combo(ui: &mut egui::Ui, config: &mut ConfigPanelState) {
    egui::ComboBox::from_id_salt("serial_baud_rate")
        .width(110.0)
        .selected_text(config.baud_rate.to_string())
        .show_ui(ui, |ui| {
            for baud_rate in [
                9_600, 19_200, 38_400, 57_600, 115_200, 230_400, 460_800, 921_600,
            ] {
                ui.selectable_value(&mut config.baud_rate, baud_rate, baud_rate.to_string());
            }
        });
}

fn parity_combo(ui: &mut egui::Ui, config: &mut ConfigPanelState) {
    egui::ComboBox::from_id_salt("serial_parity")
        .width(110.0)
        .selected_text(match config.parity {
            Parity::None => "无",
            Parity::Odd => "奇",
            Parity::Even => "偶",
        })
        .show_ui(ui, |ui| {
            ui.selectable_value(&mut config.parity, Parity::None, "无");
            ui.selectable_value(&mut config.parity, Parity::Odd, "奇");
            ui.selectable_value(&mut config.parity, Parity::Even, "偶");
        });
}

pub fn draw_stats_panel(ctx: &egui::Context, panel: &mut FloatingPanelState) {
    draw_floating_panel(ctx, panel, "统计", "stats_panel", |ui| {
        ui.horizontal(|ui| {
            ui.colored_label(accent_text(), "0.030");
            ui.label(style::subtle_text("81m:51s"));
        });
        ui.separator();
        group_frame().show(ui, |ui| {
            ui.label(style::field_label("帧率 / GPU 信息"));
            ui.label(style::value_text("边界   589.0us"));
            ui.label(style::value_text("簇     12.8ms"));
        });
    });
}

fn draw_floating_panel(
    ctx: &egui::Context,
    panel: &mut FloatingPanelState,
    title: &'static str,
    id: &'static str,
    add_contents: impl FnOnce(&mut egui::Ui),
) {
    if panel.visible {
        let mut open = true;
        let mut hide_requested = false;
        let mut window_rect = None;

        let window_response = egui::Window::new(title)
            .id(egui::Id::new(id))
            .open(&mut open)
            .default_pos(panel.default_pos)
            .title_bar(false)
            .resizable(true)
            .frame(panel_frame(ctx))
            .show(ctx, |ui| {
                ui.spacing_mut().item_spacing = egui::vec2(METRICS.item_gap, 6.0);
                ui.horizontal(|ui| {
                    if ui.add(tag_button("隐藏")).clicked() {
                        hide_requested = true;
                    }
                    ui.add_space(6.0);
                    ui.label(style::panel_title(title));
                });
                ui.separator();
                add_contents(ui);
            });

        if let Some(response) = window_response {
            window_rect = Some(response.response.rect);
        }

        if hide_requested {
            if let Some(rect) = window_rect {
                let screen = ctx.content_rect();
                let tag_size = egui::vec2(86.0, 22.0);

                let distance_to_left = rect.left();
                let distance_to_right = screen.right() - rect.right();

                let x = if distance_to_left <= distance_to_right {
                    screen.left()
                } else {
                    screen.right() - tag_size.x
                };

                let y = rect.top().clamp(screen.top(), screen.bottom() - tag_size.y);

                panel.tag_pos = egui::pos2(x, y);
            }
        }
        panel.visible = open && !hide_requested;
    }
    // else {
    //     let response = egui::Area::new(egui::Id::new(format!("{id}_tag")))
    //         .current_pos(panel.tag_pos)
    //         .movable(true)
    //         .order(egui::Order::Foreground)
    //         .show(ctx, |ui| {
    //             ui.set_min_width(86.0);
    //             if ui
    //                 .add(tag_button(format!("▸ {title}")).min_size(egui::vec2(86.0, 22.0)))
    //                 .clicked()
    //             {
    //                 panel.visible = true;
    //             }
    //         });

    //     panel.tag_pos = response.response.rect.min;
    // }
}

fn draw_center_floating_panel(
    ctx: &egui::Context,
    panel: &mut FloatingPanelState,
    id: &'static str,
    top_offset: f32,
    collapsed_label: &'static str,
    add_contents: impl FnOnce(&mut egui::Ui),
) {
    const PANEL_WIDTH: f32 = 520.0;
    const SLIDE_DISTANCE: f32 = 18.0;

    let anim = advance_center_panel_anim(ctx, panel);
    let eased = ease_in_out(anim);

    if !panel.visible || anim < 0.28 {
        let handle_y = top_offset - (1.0 - eased) * 2.0;
        egui::Area::new(egui::Id::new(format!("{id}_handle")))
            .anchor(egui::Align2::CENTER_TOP, egui::vec2(0.0, handle_y))
            .order(egui::Order::Tooltip)
            .show(ctx, |ui| {
                let handle_rect = ui
                    .allocate_exact_size(egui::vec2(112.0, 24.0), egui::Sense::hover())
                    .0;
                if integrated_handle(ui, handle_rect, collapsed_label, false, "打开连接面板")
                    .clicked()
                {
                    panel.visible = true;
                }
            });
    }

    if anim <= 0.02 {
        return;
    }

    egui::Area::new(egui::Id::new(id))
        .anchor(
            egui::Align2::CENTER_TOP,
            egui::vec2(0.0, top_offset - (1.0 - eased) * SLIDE_DISTANCE),
        )
        .order(egui::Order::Tooltip)
        .show(ctx, |ui| {
            let response = center_panel_shell(ui, PANEL_WIDTH, |ui| {
                ui.set_width(PANEL_WIDTH);
                add_contents(ui);
                ui.add_space(6.0);
                let handle_rect = allocate_center_panel_handle(ui);
                if integrated_handle(ui, handle_rect, "", true, "收起连接面板").clicked() {
                    panel.visible = false;
                }
                handle_rect
            });
            paint_integrated_center_panel(ui, response.response.rect, response.inner, true);
        });
}

fn advance_center_panel_anim(ctx: &egui::Context, panel: &mut FloatingPanelState) -> f32 {
    let target = if panel.visible { 1.0 } else { 0.0 };
    let now = ctx.input(|input| input.time);
    let delta_time = panel
        .center_anim_last_time
        .map(|last_time| (now - last_time) as f32)
        .unwrap_or(1.0 / 60.0)
        .clamp(0.0, 0.05);

    panel.center_anim_last_time = Some(now);
    panel.center_anim_target = panel.visible;

    let speed = 7.5;
    let step = speed * delta_time;
    if panel.center_anim < target {
        panel.center_anim = (panel.center_anim + step).min(target);
    } else if panel.center_anim > target {
        panel.center_anim = (panel.center_anim - step).max(target);
    }

    if (panel.center_anim - target).abs() > 0.001 {
        ctx.request_repaint();
    }

    panel.center_anim
}

fn ease_in_out(t: f32) -> f32 {
    let t = t.clamp(0.0, 1.0);
    t * t * (3.0 - 2.0 * t)
}

fn center_panel_shell<R>(
    ui: &mut egui::Ui,
    width: f32,
    add_contents: impl FnOnce(&mut egui::Ui) -> R,
) -> egui::InnerResponse<R> {
    style::center_panel_frame().show(ui, |ui| {
        ui.set_width(width);
        add_contents(ui)
    })
}

fn allocate_center_panel_handle(ui: &mut egui::Ui) -> egui::Rect {
    let handle_width = 112.0;
    let handle_height = 24.0;
    let left_space = ((ui.available_width() - handle_width) * 0.5).max(0.0);
    let mut handle_rect = egui::Rect::NOTHING;

    ui.horizontal(|ui| {
        ui.add_space(left_space);
        let (rect, _) = ui.allocate_exact_size(
            egui::vec2(handle_width, handle_height),
            egui::Sense::hover(),
        );
        handle_rect = rect;
    });

    handle_rect
}

fn integrated_handle(
    ui: &mut egui::Ui,
    rect: egui::Rect,
    label: &str,
    expanded: bool,
    tooltip: &'static str,
) -> egui::Response {
    let response = ui
        .interact(
            rect.expand2(egui::vec2(12.0, 5.0)),
            ui.id().with(("center_panel_handle", expanded)),
            egui::Sense::click(),
        )
        .on_hover_text(tooltip);

    paint_integrated_handle(ui, rect, label, expanded, response.hovered());
    response
}

fn paint_integrated_handle(
    ui: &mut egui::Ui,
    rect: egui::Rect,
    label: &str,
    expanded: bool,
    hovered: bool,
) {
    let center = rect.center();
    if !expanded {
        let fill = if hovered {
            ONE_DARK_PRO.panel_strong
        } else {
            egui::Color32::from_rgb(31, 41, 52)
        };
        let points = vec![
            egui::pos2(rect.left() - 12.0, rect.top() - 1.0),
            egui::pos2(rect.right() + 12.0, rect.top() - 1.0),
            egui::pos2(rect.right() + 3.0, rect.bottom() + 8.0),
            egui::pos2(rect.left() - 3.0, rect.bottom() + 8.0),
        ];
        ui.painter().add(egui::Shape::convex_polygon(
            points.clone(),
            fill,
            egui::Stroke::new(1.0, ONE_DARK_PRO.border),
        ));
        ui.painter().line_segment(
            [points[2], points[3]],
            egui::Stroke::new(1.0, ONE_DARK_PRO.border_soft),
        );
    }

    let arrow = if expanded { -1.0 } else { 1.0 };
    let arrow_center_x = if label.is_empty() {
        center.x
    } else {
        rect.right() - 18.0
    };
    let arrow_center = egui::pos2(arrow_center_x, center.y);
    let arrow_color = if hovered {
        ONE_DARK_PRO.accent_hot
    } else {
        ONE_DARK_PRO.text_dim
    };
    ui.painter().line_segment(
        [
            arrow_center + egui::vec2(-6.0, -2.0 * arrow),
            arrow_center + egui::vec2(0.0, 4.0 * arrow),
        ],
        egui::Stroke::new(1.7, arrow_color),
    );
    ui.painter().line_segment(
        [
            arrow_center + egui::vec2(6.0, -2.0 * arrow),
            arrow_center + egui::vec2(0.0, 4.0 * arrow),
        ],
        egui::Stroke::new(1.7, arrow_color),
    );

    if !label.is_empty() {
        let galley = ui.fonts_mut(|fonts| {
            fonts.layout_no_wrap(
                label.to_owned(),
                egui::FontId::proportional(12.0),
                ONE_DARK_PRO.text,
            )
        });
        ui.painter().galley(
            egui::pos2(rect.left() + 14.0, center.y - galley.size().y * 0.5 - 1.0),
            galley,
            ONE_DARK_PRO.text,
        );
    }
}

fn paint_integrated_center_panel(
    ui: &egui::Ui,
    rect: egui::Rect,
    handle_rect: egui::Rect,
    handle_on_bottom: bool,
) {
    let painter = ui.painter();
    let stroke = egui::Stroke::new(1.0, ONE_DARK_PRO.border);
    let accent_stroke = egui::Stroke::new(1.2, ONE_DARK_PRO.border_soft);
    let top = rect.top();
    let left = rect.left();
    let right = rect.right();
    let bottom = rect.bottom();
    let radius = ONE_DARK_PRO.radius as f32;
    let tab_left = handle_rect.left() - 18.0;
    let tab_right = handle_rect.right() + 18.0;
    let tab_recess = if handle_on_bottom {
        handle_rect.top() - 2.0
    } else {
        handle_rect.bottom() + 2.0
    };

    if handle_on_bottom {
        painter.line_segment(
            [
                egui::pos2(left + radius, top),
                egui::pos2(right - radius, top),
            ],
            stroke,
        );
    } else {
        painter.line_segment(
            [egui::pos2(left + radius, top), egui::pos2(tab_left, top)],
            stroke,
        );
        painter.line_segment(
            [egui::pos2(tab_right, top), egui::pos2(right - radius, top)],
            stroke,
        );
    }
    painter.line_segment(
        [
            egui::pos2(left, top + radius),
            egui::pos2(left, bottom - radius),
        ],
        stroke,
    );
    painter.line_segment(
        [
            egui::pos2(right, top + radius),
            egui::pos2(right, bottom - radius),
        ],
        stroke,
    );
    if handle_on_bottom {
        painter.line_segment(
            [
                egui::pos2(left + radius, bottom),
                egui::pos2(tab_left, bottom),
            ],
            stroke,
        );
        painter.line_segment(
            [
                egui::pos2(tab_right, bottom),
                egui::pos2(right - radius, bottom),
            ],
            stroke,
        );
    } else {
        painter.line_segment(
            [
                egui::pos2(left + radius, bottom),
                egui::pos2(right - radius, bottom),
            ],
            stroke,
        );
    }

    let tab_points = if handle_on_bottom {
        vec![
            egui::pos2(tab_left, bottom),
            egui::pos2(handle_rect.left() - 8.0, tab_recess),
            egui::pos2(handle_rect.right() + 8.0, tab_recess),
            egui::pos2(tab_right, bottom),
        ]
    } else {
        vec![
            egui::pos2(tab_left, top),
            egui::pos2(handle_rect.left() - 8.0, tab_recess),
            egui::pos2(handle_rect.right() + 8.0, tab_recess),
            egui::pos2(tab_right, top),
        ]
    };
    painter.add(egui::Shape::line(tab_points, accent_stroke));
}

// ── Signal Chart (sparkline) ───────────────────────────────────────────

/// Draw a mini sparkline chart with current/min/max labels.
pub fn draw_signal_chart(ui: &mut egui::Ui, values: &[f32], label: &str, color: egui::Color32) {
    let chart_height = 48.0;
    let chart_width = ui.available_width().min(200.0);

    group_frame().show(ui, |ui| {
        ui.horizontal(|ui| {
            ui.colored_label(color, label);
            if let (Some(&last), Some(&min), Some(&max)) = (
                values.last(),
                values
                    .iter()
                    .min_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal)),
                values
                    .iter()
                    .max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal)),
            ) {
                ui.colored_label(ONE_DARK_PRO.text, format!("{:.0}", last));
                ui.colored_label(ONE_DARK_PRO.text_dim, format!("↓{:.0} ↑{:.0}", min, max));
            }
        });

        let (rect, _response) =
            ui.allocate_exact_size(egui::vec2(chart_width, chart_height), egui::Sense::hover());

        if values.len() < 2 {
            return;
        }

        let painter = ui.painter_at(rect);
        painter.rect_filled(rect, egui::CornerRadius::same(2), ONE_DARK_PRO.panel_deep);

        let min_val = values
            .iter()
            .min_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
            .copied()
            .unwrap_or(0.0);
        let max_val = values
            .iter()
            .max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
            .copied()
            .unwrap_or(1.0);
        let range = (max_val - min_val).max(1.0);

        let points: Vec<egui::Pos2> = values
            .iter()
            .enumerate()
            .map(|(i, &v)| {
                let x = rect.left() + (i as f32 / (values.len() - 1) as f32) * rect.width();
                let y = rect.bottom() - ((v - min_val) / range) * rect.height();
                egui::pos2(x, y)
            })
            .collect();

        painter.add(egui::Shape::line(points, egui::Stroke::new(1.5, color)));
    });
}

// ── Recording Toolbar ──────────────────────────────────────────────────

/// Draw recording controls inside the connect panel.
pub fn draw_recording_toolbar(ui: &mut egui::Ui, recorder: &Recorder, export_path: &mut String) {
    let is_recording = recorder.is_recording();
    let frame_count = recorder.frame_count();
    let duration_ms = recorder.duration_ms();

    ui.separator();
    ui.horizontal(|ui| {
        ui.colored_label(ACCENT_RED, "● REC");
        ui.colored_label(
            ONE_DARK_PRO.text,
            format!("{} 帧 | {:.1}s", frame_count, duration_ms as f64 / 1000.0),
        );
    });

    ui.horizontal(|ui| {
        // Full recording
        let rec_btn = if is_recording {
            tag_button("⏹ 停止")
        } else {
            style::accent_button(
                egui::RichText::new("● 全量录制").color(egui::Color32::WHITE),
                ACCENT_RED,
            )
        };
        if ui.add(rec_btn).clicked() {
            if is_recording {
                let _ = recorder.stop_recording();
            } else {
                let _ = recorder.start_full_recording();
            }
        }

        ui.add_space(4.0);

        // Snapshot recording
        let snap_btn = if is_recording {
            tag_button("⏹ 快照停止")
        } else {
            style::accent_button(
                egui::RichText::new("✂ 快照录制").color(egui::Color32::WHITE),
                ACCENT_ORANGE,
            )
        };
        if ui.add(snap_btn).clicked() {
            if is_recording {
                let _ = recorder.stop_recording();
            } else {
                let _ = recorder.start_snapshot_recording();
            }
        }

        ui.add_space(4.0);

        // Pause/Resume
        if is_recording {
            if ui.add(tag_button("⏸ 暂停")).clicked() {
                let _ = recorder.pause_recording();
            }
        }

        ui.add_space(8.0);

        // Export
        if ui
            .add(style::accent_button(
                egui::RichText::new("📤 导出CSV").color(egui::Color32::WHITE),
                ACCENT_BLUE,
            ))
            .clicked()
        {
            let path = if export_path.is_empty() {
                let ts = std::time::SystemTime::now()
                    .duration_since(std::time::UNIX_EPOCH)
                    .unwrap_or_default()
                    .as_secs();
                format!("eskin_export_{}.csv", ts)
            } else {
                export_path.clone()
            };
            if let Err(e) = recorder.export_csv(&path) {
                eprintln!("[export] error: {e}");
            }
        }

        // Import
        if ui
            .add(style::accent_button(
                egui::RichText::new("📥 导入CSV").color(egui::Color32::WHITE),
                ACCENT_GREEN,
            ))
            .clicked()
        {
            let import_path = export_path.clone();
            if let Err(e) = recorder.import_csv(&import_path) {
                eprintln!("[import] error: {e}");
            }
        }
    });

    // Export path
    ui.horizontal(|ui| {
        ui.colored_label(dim_text(), "导出路径");
        ui.add_sized(
            egui::vec2(
                (ui.available_width() - 80.0).max(160.0),
                METRICS.field_height,
            ),
            egui::TextEdit::singleline(export_path).hint_text("eskin_export_*.csv"),
        );
    });
}

// ── Export Panel (floating) ────────────────────────────────────────────

/// Draw the export/recording floating panel.
pub fn draw_export_panel(
    ctx: &egui::Context,
    panel: &mut FloatingPanelState,
    recorder: &Recorder,
    export_path: &mut String,
) {
    draw_floating_panel(ctx, panel, "录制导出", "export_panel", |ui| {
        ui.set_min_width(300.0);
        draw_recording_toolbar(ui, recorder, export_path);
    });
}

// ── Matrix Config Panel ────────────────────────────────────────────────

pub struct MatrixConfigState {
    pub rows: u32,
    pub cols: u32,
    pub color_min: f32,
    pub color_max: f32,
}

impl Default for MatrixConfigState {
    fn default() -> Self {
        Self {
            rows: 12,
            cols: 7,
            color_min: 0.0,
            color_max: 7000.0,
        }
    }
}

/// Draw matrix configuration floating panel.
pub fn draw_matrix_config_panel(
    ctx: &egui::Context,
    panel: &mut FloatingPanelState,
    config: &mut MatrixConfigState,
) {
    draw_floating_panel(ctx, panel, "矩阵配置", "matrix_config_panel", |ui| {
        ui.set_min_width(280.0);

        ui.horizontal(|ui| {
            ui.label(style::field_label("矩阵尺寸"));
            ui.add_space(METRICS.item_gap);
            ui.label(style::value_text("行"));
            ui.add_sized(
                egui::vec2(56.0, METRICS.field_height),
                egui::DragValue::new(&mut config.rows).range(1..=128),
            );
            ui.label(style::value_text("列"));
            ui.add_sized(
                egui::vec2(56.0, METRICS.field_height),
                egui::DragValue::new(&mut config.cols).range(1..=128),
            );
        });

        ui.add_space(METRICS.item_gap);

        ui.horizontal(|ui| {
            ui.label(style::field_label("预设"));
            for (r, c, name) in &[
                (12, 7, "12×7"),
                (24, 12, "24×12"),
                (32, 16, "32×16"),
                (48, 24, "48×24"),
                (64, 32, "64×32"),
            ] {
                if ui.add(tag_button(*name)).clicked() {
                    config.rows = *r;
                    config.cols = *c;
                }
            }
        });

        ui.add_space(METRICS.item_gap);

        ui.horizontal(|ui| {
            ui.label(style::field_label("色域范围"));
            ui.add_space(METRICS.item_gap);
            ui.label(style::value_text("最小"));
            ui.add_sized(
                egui::vec2(72.0, METRICS.field_height),
                egui::DragValue::new(&mut config.color_min)
                    .range(0.0..=10000.0)
                    .speed(100.0),
            );
            ui.label(style::value_text("最大"));
            ui.add_sized(
                egui::vec2(72.0, METRICS.field_height),
                egui::DragValue::new(&mut config.color_max)
                    .range(1.0..=10000.0)
                    .speed(100.0),
            );
        });

        ui.add_space(METRICS.row_gap);

        if ui.add(tag_button("重置默认")).clicked() {
            *config = MatrixConfigState::default();
        }
    });
}

pub fn panel_restore_item(ui: &mut egui::Ui, title: &'static str, panel: &mut FloatingPanelState) {
    if panel.visible {
        ui.add_enabled(false, egui::Button::new(format!("{title} 已显示")));
    } else if ui.button(format!("显示 {title}")).clicked() {
        panel.visible = true;
        ui.close();
    }
}
