"""面板管理器（Step 6 重构）。

register_panel / show_panel / hide_all_panels —— 在右侧栏不同浮动面板间切换。
"""

from __future__ import annotations

import tkinter as tk
import tkinter.font as tkfont

from typing import TYPE_CHECKING, Any, Callable

if TYPE_CHECKING:
    from pqAutomationApp import PQAutomationApp

# 叠层切换：lift/lower，避免 pack_forget 触发 Matplotlib 等大面板重绘。
_STACK_PANELS = frozenset(
    {"log", "ai_image", "pantone_baseline", "gamma_pattern", "calman", "single_step"}
)


def create_tool_panel_sidebar_item(
    self: "PQAutomationApp", parent: tk.Misc, label: str, command: Callable[[], None]
) -> dict[str, Any]:
    """创建工具面板侧栏项：名称左对齐，选中时 × 贴右端，整体可点击。"""
    from app.views.modern_styles import _contrast_text, _is_dark, get_theme_palette

    row = tk.Frame(parent, bd=0, highlightthickness=0, cursor="hand2")
    name_lbl = tk.Label(row, text=label, anchor=tk.W, bd=0, padx=18, pady=9)
    close_lbl = tk.Label(
        row,
        text="×",
        anchor=tk.CENTER,
        bd=0,
        padx=0,
        pady=9,
        width=2,
        font=("Segoe UI", 9),
    )
    name_lbl.pack(side=tk.LEFT, fill=tk.X, expand=True)

    item: dict[str, Any] = {
        "row": row,
        "name_label": name_lbl,
        "close_label": close_lbl,
        "label": label,
        "selected": False,
        "hover": False,
    }

    def _apply_style() -> None:
        palette = get_theme_palette()
        sidebar_bg = palette["sidebar_bg"]
        sidebar_hover = palette["sidebar_hover"]
        sidebar_selected = palette["sidebar_selected"]
        sidebar_fg = palette["sidebar_fg"]
        selected_fg = _contrast_text(
            sidebar_selected,
            dark_text=palette["badge_fg"],
            light_text=sidebar_fg,
        )

        if item["selected"]:
            bg = sidebar_selected
            fg = selected_fg
            name_font = ("Segoe UI Semibold", 10)
        elif item["hover"]:
            bg = sidebar_hover
            fg = "#ffffff" if _is_dark(sidebar_hover) else sidebar_fg
            name_font = ("Segoe UI", 10)
        else:
            bg = sidebar_bg
            fg = sidebar_fg
            name_font = ("Segoe UI", 10)

        row.configure(bg=bg)
        for widget in (name_lbl, close_lbl):
            widget.configure(
                bg=bg,
                fg=fg,
                activebackground=bg,
                activeforeground=fg,
            )
        name_lbl.configure(font=name_font)

    def _truncate_name() -> None:
        full = item["label"]
        if not item["selected"]:
            name_lbl.configure(text=full)
            return

        row.update_idletasks()
        close_w = close_lbl.winfo_width() if close_lbl.winfo_ismapped() else 20
        avail = max(24, row.winfo_width() - close_w - 18 - 14)
        font = tkfont.Font(font=name_lbl.cget("font"))
        if font.measure(full) <= avail:
            name_lbl.configure(text=full)
            return
        for i in range(len(full), 0, -1):
            candidate = full[:i].rstrip() + "…"
            if font.measure(candidate) <= avail:
                name_lbl.configure(text=candidate)
                return
        name_lbl.configure(text="…")

    def set_selected(selected: bool) -> None:
        item["selected"] = selected
        if selected:
            close_lbl.pack(side=tk.RIGHT, padx=(0, 14))
        else:
            close_lbl.pack_forget()
        _apply_style()
        row.after_idle(_truncate_name)

    def _on_click(_event=None) -> None:
        command()

    def _on_enter(_event=None) -> None:
        if not item["selected"]:
            item["hover"] = True
            _apply_style()

    def _on_leave(_event=None) -> None:
        px, py = row.winfo_pointerxy()
        rx, ry = row.winfo_rootx(), row.winfo_rooty()
        rw, rh = row.winfo_width(), row.winfo_height()
        if rx <= px < rx + rw and ry <= py < ry + rh:
            return
        item["hover"] = False
        _apply_style()

    def _on_configure(_event=None) -> None:
        if item["selected"]:
            _truncate_name()

    for widget in (row, name_lbl, close_lbl):
        widget.bind("<Button-1>", _on_click)
        widget.bind("<Enter>", _on_enter)
        widget.bind("<Leave>", _on_leave)
    row.bind("<Configure>", _on_configure)

    item["set_selected"] = set_selected
    item["apply_theme"] = _apply_style
    item["pack"] = lambda **kw: row.pack(fill=tk.X, padx=0, pady=1, **kw)

    _apply_style()
    return item


def _set_tool_panel_sidebar_selected(
    panel_info: dict[str, Any], selected: bool
) -> None:
    sidebar_item = panel_info.get("sidebar_item")
    if sidebar_item is not None:
        sidebar_item["set_selected"](selected)
        return
    button = panel_info.get("button")
    if button is not None:
        button.configure(
            style="SidebarSelected.TButton" if selected else "Sidebar.TButton"
        )


def refresh_tool_panel_sidebar_theme(self: "PQAutomationApp") -> None:
    """主题切换后刷新工具面板侧栏项配色。"""
    for panel_info in self.panels.values():
        sidebar_item = panel_info.get("sidebar_item")
        if sidebar_item is not None:
            sidebar_item["apply_theme"]()


def register_panel(self: "PQAutomationApp", panel_name, frame, button, visible_attr):
    """注册一个面板到管理系统"""
    self.panels[panel_name] = {
        "frame": frame,
        "button": button,
        "button_label": None,
        "sidebar_item": None,
        "visible_attr": visible_attr,
    }


def setup_view_stack(self: "PQAutomationApp") -> None:
    """将所有工具面板叠放在 view_stack 上，切换时仅调整 Z 序。"""
    if getattr(self, "_view_stack_ready", False):
        return

    self.main_view.place(relx=0, rely=0, relwidth=1, relheight=1)
    for panel_name, panel_info in self.panels.items():
        if panel_name == "local_dimming":
            continue
        panel_info["frame"].place(relx=0, rely=0, relwidth=1, relheight=1)
        panel_info["frame"].lower()

    self._view_stack_ready = True


def _lower_stack_panels(self: "PQAutomationApp") -> None:
    for panel_name, panel_info in self.panels.items():
        if panel_name in _STACK_PANELS:
            panel_info["frame"].lower()


def _clear_panel_selection(self: "PQAutomationApp") -> None:
    for panel_info in self.panels.values():
        _set_tool_panel_sidebar_selected(panel_info, False)
        setattr(self, panel_info["visible_attr"], False)


def _restore_main_view_layout(self: "PQAutomationApp") -> None:
    """恢复主界面三区布局，并收起嵌入的 Local Dimming 面板。"""
    if getattr(self, "_ld_embedded", False):
        self.local_dimming_frame.pack_forget()
        self._ld_embedded = False

    self.control_frame_top.pack_forget()
    self.control_frame_middle.pack_forget()
    self.control_frame_bottom.pack_forget()
    self.control_frame_top.pack(
        side=tk.TOP, fill=tk.BOTH, expand=True, padx=0, pady=5
    )
    self.control_frame_middle.pack(
        side=tk.TOP, fill=tk.BOTH, expand=True, padx=0, pady=5
    )
    self.control_frame_bottom.pack(
        side=tk.TOP, fill=tk.BOTH, expand=True, padx=0, pady=5
    )


def _show_main_content(self: "PQAutomationApp") -> None:
    """显示主内容区并清除当前面板状态。"""
    setup_view_stack(self)
    _lower_stack_panels(self)
    _restore_main_view_layout(self)
    self.main_view.lift()
    _clear_panel_selection(self)
    self.current_panel = None

    if hasattr(self, "_sync_save_button_state"):
        try:
            self._sync_save_button_state()
        except Exception:
            pass


def _notify_panel_shown(self: "PQAutomationApp", panel_name: str) -> None:
    """面板显示后的轻量刷新（延迟执行，不阻塞切换）。"""
    if panel_name == "calman":
        refresh = getattr(self, "_on_calman_panel_shown", None)
        if refresh is not None:
            self.root.after_idle(refresh)


def _show_stack_panel(self: "PQAutomationApp", panel_name: str) -> None:
    """叠层模式显示工具面板。"""
    setup_view_stack(self)
    panel_info = self.panels[panel_name]

    _set_tool_panel_sidebar_selected(panel_info, True)

    previous = self.current_panel
    if previous == "local_dimming":
        self.local_dimming_frame.pack_forget()
        self._ld_embedded = False
    elif previous is not None and previous in _STACK_PANELS:
        prev_info = self.panels[previous]
        _set_tool_panel_sidebar_selected(prev_info, False)
        setattr(self, prev_info["visible_attr"], False)
        prev_info["frame"].lower()

    self.main_view.lower()
    panel_info["frame"].lift()
    setattr(self, panel_info["visible_attr"], True)
    self.current_panel = panel_name
    _notify_panel_shown(self, panel_name)


def _show_local_dimming_panel(self: "PQAutomationApp") -> None:
    """Local Dimming：保留顶部配置区，下方嵌入 LD 面板。"""
    setup_view_stack(self)
    panel_info = self.panels["local_dimming"]

    if self.current_panel in _STACK_PANELS:
        prev_info = self.panels[self.current_panel]
        _set_tool_panel_sidebar_selected(prev_info, False)
        setattr(self, prev_info["visible_attr"], False)
        prev_info["frame"].lower()

    _set_tool_panel_sidebar_selected(panel_info, True)
    _lower_stack_panels(self)
    self.main_view.lift()

    self.control_frame_top.pack_forget()
    self.control_frame_top.pack(
        side=tk.TOP, fill=tk.X, expand=False, padx=0, pady=5
    )
    self.control_frame_middle.pack_forget()
    self.control_frame_bottom.pack_forget()
    self.local_dimming_frame.pack(
        side=tk.TOP, fill=tk.BOTH, expand=True, padx=5, pady=5
    )
    self._ld_embedded = True

    setattr(self, panel_info["visible_attr"], True)
    self.current_panel = "local_dimming"


def _maybe_restore_local_dimming_panel(
    self: "PQAutomationApp", closed_panel: str
) -> None:
    """关闭工具面板后，Local Dimming 测试类型下自动恢复 LD 面板。"""
    if closed_panel == "local_dimming":
        return
    try:
        if (
            getattr(self, "config", None)
            and getattr(self.config, "current_test_type", None) == "local_dimming"
        ):
            self.show_panel("local_dimming")
    except Exception:
        pass


def show_panel(self: "PQAutomationApp", panel_name):
    """显示指定面板，隐藏其他所有面板"""
    if panel_name not in self.panels:
        return

    if self.current_panel == panel_name:
        _show_main_content(self)
        _maybe_restore_local_dimming_panel(self, panel_name)
        return

    if panel_name == "local_dimming":
        _show_local_dimming_panel(self)
        return

    if panel_name in _STACK_PANELS:
        _show_stack_panel(self, panel_name)
        return

    # 未知面板类型：回退到叠层显示
    _show_stack_panel(self, panel_name)


def hide_all_panels(self: "PQAutomationApp"):
    """隐藏所有面板，显示主内容区域"""
    _show_main_content(self)


class PanelManagerMixin:
    """由 tools/refactor_to_mixins.py 自动生成。
    把本模块的自由函数挂到 PQAutomationApp 上，便于 F12 跳转与类型推断。
    """
    create_tool_panel_sidebar_item = create_tool_panel_sidebar_item
    register_panel = register_panel
    setup_view_stack = setup_view_stack
    show_panel = show_panel
    hide_all_panels = hide_all_panels
    refresh_tool_panel_sidebar_theme = refresh_tool_panel_sidebar_theme
