"""CCT 参数面板及其处理函数（与主文件重构版本保持同步）。"""

import time
import traceback
from tkinter import messagebox
import tkinter as tk
import ttkbootstrap as ttk

import algorithm.pq_algorithm as pq_algorithm

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from pqAutomationApp import PQAutomationApp


def _theme_colors():
    style = ttk.Style()
    colors = style.colors
    return {
        "muted": colors.secondary,
    }



def create_cct_params_frame(self: "PQAutomationApp"):
    """创建色度参数设置区域 - 屏模组、SDR、HDR 独立（增加色域参考标准选择 + 单步调试按钮）"""

    # ==================== 屏模组色度参数 Frame ====================
    self.cct_params_frame = ttk.LabelFrame(
        self.test_items_frame, text="色度参数设置（屏模组）"
    )

    # 默认值
    screen_default_cct_params = self.config.get_default_cct_params("screen_module")

    # 从配置读取屏模组参数
    saved_params = self.config.current_test_types.get("screen_module", {}).get(
        "cct_params", {}
    )

    # 色域参考标准
    saved_gamut_ref = self.config.current_test_types.get("screen_module", {}).get(
        "gamut_reference", self.config.get_default_gamut_reference("screen_module")
    )

    # 创建屏模组变量
    self.cct_x_ideal_var = tk.StringVar(value="")
    self.cct_x_tolerance_var = tk.StringVar(
        value=str(saved_params.get("x_tolerance", 0.003))
    )
    self.cct_y_ideal_var = tk.StringVar(value="")
    self.cct_y_tolerance_var = tk.StringVar(
        value=str(saved_params.get("y_tolerance", 0.003))
    )
    self.screen_gamut_ref_var = tk.StringVar(value=saved_gamut_ref)

    # 创建屏模组输入框（左侧：色度参数）
    params = [
        ("x-ideal:", self.cct_x_ideal_var, "x_ideal"),
        ("x-tolerance:", self.cct_x_tolerance_var, "x_tolerance"),
        ("y-ideal:", self.cct_y_ideal_var, "y_ideal"),
        ("y-tolerance:", self.cct_y_tolerance_var, "y_tolerance"),
    ]

    for i, (label_text, var, key) in enumerate(params):
        ttk.Label(self.cct_params_frame, text=label_text).grid(
            row=i, column=0, sticky=tk.W, padx=5, pady=3
        )
        entry = ttk.Entry(self.cct_params_frame, textvariable=var, width=15)
        entry.grid(row=i, column=1, sticky=tk.W, padx=5, pady=3)

        # 屏模组中心由实测 100% 点自动决定，避免手动误改。
        if key in ("x_ideal", "y_ideal"):
            entry.configure(state="readonly")
        else:
            # 绑定失去焦点事件
            default_val = screen_default_cct_params[key]
            entry.bind(
                "<FocusOut>",
                lambda e, v=var, d=default_val: self.on_cct_param_focus_out(v, d),
            )

    # 色域参考标准选择（右侧第一行）
    ttk.Label(self.cct_params_frame, text="色域参考标准:").grid(
        row=0, column=2, sticky=tk.W, padx=(20, 5), pady=3
    )
    screen_gamut_combo = ttk.Combobox(
        self.cct_params_frame,
        textvariable=self.screen_gamut_ref_var,
        values=["BT.2020", "BT.709", "DCI-P3"],
        state="disabled",
        width=12,
    )
    screen_gamut_combo.grid(row=0, column=3, sticky=tk.W, padx=5, pady=3)
    screen_gamut_combo.bind(
        "<<ComboboxSelected>>", self.on_screen_gamut_ref_changed
    )
    self.screen_gamut_combo = screen_gamut_combo

    # ==================== 单步调试按钮（右侧第二行）====================
    ttk.Label(self.cct_params_frame, text="单步调试:").grid(
        row=1, column=2, sticky=tk.W, padx=(20, 5), pady=3
    )

    self.screen_debug_btn = ttk.Button(
        self.cct_params_frame,
        text="打开调试面板",
        command=self.toggle_screen_debug_panel,
        bootstyle="info-outline",
        state=tk.DISABLED,  # 初始禁用
        width=15,
    )
    self.screen_debug_btn.grid(row=1, column=3, sticky=tk.W, padx=5, pady=3)

    # 重新计算按钮（屏模组）
    self.recalc_cct_btn = ttk.Button(
        self.cct_params_frame,
        text="应用新参数并重绘",
        command=self.recalculate_cct,
        bootstyle="success",
    )
    self.recalc_cct_btn.grid(
        row=4, column=0, columnspan=2, pady=10, padx=5, sticky="ew"
    )
    self.recalc_cct_btn.grid_remove()

    # 提示文字
    ttk.Label(
        self.cct_params_frame,
        text="提示: 清空输入框将恢复默认值",
        font=("SimHei", 8),
        foreground=_theme_colors()["muted"],
    ).grid(row=5, column=0, columnspan=4, sticky=tk.W, padx=5, pady=5)

    # ==================== SDR 色度参数 Frame ====================
    self.sdr_cct_params_frame = ttk.LabelFrame(
        self.test_items_frame, text="色度参数设置（SDR）"
    )

    # SDR 默认值
    sdr_default_cct_params = self.config.get_default_cct_params("sdr_movie")

    # 从配置读取 SDR 参数
    sdr_saved_params = self.config.current_test_types.get("sdr_movie", {}).get(
        "cct_params", sdr_default_cct_params.copy()
    )

    # 色域参考标准
    sdr_saved_gamut_ref = self.config.current_test_types.get("sdr_movie", {}).get(
        "gamut_reference", self.config.get_default_gamut_reference("sdr_movie")
    )

    # 创建 SDR 变量
    self.sdr_cct_x_ideal_var = tk.StringVar(
        value=str(sdr_saved_params.get("x_ideal", 0.3127))
    )
    self.sdr_cct_x_tolerance_var = tk.StringVar(
        value=str(sdr_saved_params.get("x_tolerance", 0.003))
    )
    self.sdr_cct_y_ideal_var = tk.StringVar(
        value=str(sdr_saved_params.get("y_ideal", 0.3290))
    )
    self.sdr_cct_y_tolerance_var = tk.StringVar(
        value=str(sdr_saved_params.get("y_tolerance", 0.003))
    )
    self.sdr_gamut_ref_var = tk.StringVar(value=sdr_saved_gamut_ref)

    # 创建 SDR 输入框
    sdr_params = [
        ("x-ideal:", self.sdr_cct_x_ideal_var, "x_ideal"),
        ("x-tolerance:", self.sdr_cct_x_tolerance_var, "x_tolerance"),
        ("y-ideal:", self.sdr_cct_y_ideal_var, "y_ideal"),
        ("y-tolerance:", self.sdr_cct_y_tolerance_var, "y_tolerance"),
    ]

    for i, (label_text, var, key) in enumerate(sdr_params):
        ttk.Label(self.sdr_cct_params_frame, text=label_text).grid(
            row=i, column=0, sticky=tk.W, padx=5, pady=3
        )
        entry = ttk.Entry(self.sdr_cct_params_frame, textvariable=var, width=15)
        entry.grid(row=i, column=1, sticky=tk.W, padx=5, pady=3)

        # 绑定失去焦点事件
        default_val = sdr_default_cct_params[key]
        entry.bind(
            "<FocusOut>",
            lambda e, v=var, d=default_val: self.on_sdr_cct_param_focus_out(v, d),
        )

    # 色域参考标准选择（右侧第一行）
    ttk.Label(self.sdr_cct_params_frame, text="色域参考标准:").grid(
        row=0, column=2, sticky=tk.W, padx=(20, 5), pady=3
    )
    sdr_gamut_combo = ttk.Combobox(
        self.sdr_cct_params_frame,
        textvariable=self.sdr_gamut_ref_var,
        values=["BT.2020", "BT.709", "DCI-P3"],
        state="disabled",
        width=12,
    )
    sdr_gamut_combo.grid(row=0, column=3, sticky=tk.W, padx=5, pady=3)
    sdr_gamut_combo.bind("<<ComboboxSelected>>", self.on_sdr_gamut_ref_changed)
    self.sdr_gamut_combo = sdr_gamut_combo

    # ==================== SDR 单步调试按钮（右侧第二行）====================
    ttk.Label(self.sdr_cct_params_frame, text="单步调试:").grid(
        row=1, column=2, sticky=tk.W, padx=(20, 5), pady=3
    )

    self.sdr_debug_btn = ttk.Button(
        self.sdr_cct_params_frame,
        text="打开调试面板",
        command=self.toggle_sdr_debug_panel,
        bootstyle="info-outline",
        state=tk.DISABLED,  # 初始禁用
        width=15,
    )
    self.sdr_debug_btn.grid(row=1, column=3, sticky=tk.W, padx=5, pady=3)

    # 重新计算按钮（SDR）
    self.sdr_recalc_cct_btn = ttk.Button(
        self.sdr_cct_params_frame,
        text="应用新参数并重绘",
        command=self.recalculate_cct,
        bootstyle="success",
    )
    self.sdr_recalc_cct_btn.grid(
        row=4, column=0, columnspan=2, pady=10, padx=5, sticky="ew"
    )
    self.sdr_recalc_cct_btn.grid_remove()

    # 提示文字
    ttk.Label(
        self.sdr_cct_params_frame,
        text="提示: 清空输入框将恢复默认值",
        font=("SimHei", 8),
        foreground=_theme_colors()["muted"],
    ).grid(row=5, column=0, columnspan=4, sticky=tk.W, padx=5, pady=5)

    # ==================== HDR 色度参数 Frame ====================
    self.hdr_cct_params_frame = ttk.LabelFrame(
        self.test_items_frame, text="色度参数设置（HDR）"
    )

    # HDR 默认值
    hdr_default_cct_params = self.config.get_default_cct_params("hdr_movie")

    # 从配置读取 HDR 参数
    hdr_saved_params = self.config.current_test_types.get("hdr_movie", {}).get(
        "cct_params", hdr_default_cct_params.copy()
    )

    # 色域参考标准
    hdr_saved_gamut_ref = self.config.current_test_types.get("hdr_movie", {}).get(
        "gamut_reference", self.config.get_default_gamut_reference("hdr_movie")
    )

    # 创建 HDR 变量
    self.hdr_cct_x_ideal_var = tk.StringVar(
        value=str(hdr_saved_params.get("x_ideal", 0.3127))
    )
    self.hdr_cct_x_tolerance_var = tk.StringVar(
        value=str(hdr_saved_params.get("x_tolerance", 0.003))
    )
    self.hdr_cct_y_ideal_var = tk.StringVar(
        value=str(hdr_saved_params.get("y_ideal", 0.3290))
    )
    self.hdr_cct_y_tolerance_var = tk.StringVar(
        value=str(hdr_saved_params.get("y_tolerance", 0.003))
    )
    self.hdr_gamut_ref_var = tk.StringVar(value=hdr_saved_gamut_ref)

    # 创建 HDR 输入框
    hdr_params = [
        ("x-ideal:", self.hdr_cct_x_ideal_var, "x_ideal"),
        ("x-tolerance:", self.hdr_cct_x_tolerance_var, "x_tolerance"),
        ("y-ideal:", self.hdr_cct_y_ideal_var, "y_ideal"),
        ("y-tolerance:", self.hdr_cct_y_tolerance_var, "y_tolerance"),
    ]

    for i, (label_text, var, key) in enumerate(hdr_params):
        ttk.Label(self.hdr_cct_params_frame, text=label_text).grid(
            row=i, column=0, sticky=tk.W, padx=5, pady=3
        )
        entry = ttk.Entry(self.hdr_cct_params_frame, textvariable=var, width=15)
        entry.grid(row=i, column=1, sticky=tk.W, padx=5, pady=3)

        # 绑定失去焦点事件
        default_val = hdr_default_cct_params[key]
        entry.bind(
            "<FocusOut>",
            lambda e, v=var, d=default_val: self.on_hdr_cct_param_focus_out(v, d),
        )

    # 色域参考标准选择（右侧第一行）
    ttk.Label(self.hdr_cct_params_frame, text="色域参考标准:").grid(
        row=0, column=2, sticky=tk.W, padx=(20, 5), pady=3
    )
    hdr_gamut_combo = ttk.Combobox(
        self.hdr_cct_params_frame,
        textvariable=self.hdr_gamut_ref_var,
        values=["BT.2020", "BT.709", "DCI-P3"],
        state="disabled",
        width=12,
    )
    hdr_gamut_combo.grid(row=0, column=3, sticky=tk.W, padx=5, pady=3)
    hdr_gamut_combo.bind("<<ComboboxSelected>>", self.on_hdr_gamut_ref_changed)
    self.hdr_gamut_combo = hdr_gamut_combo

    # ==================== HDR 单步调试按钮（右侧第二行）====================
    ttk.Label(self.hdr_cct_params_frame, text="单步调试:").grid(
        row=1, column=2, sticky=tk.W, padx=(20, 5), pady=3
    )

    self.hdr_debug_btn = ttk.Button(
        self.hdr_cct_params_frame,
        text="打开调试面板",
        command=self.toggle_hdr_debug_panel,
        bootstyle="info-outline",
        state=tk.DISABLED,  # 初始禁用
        width=15,
    )
    self.hdr_debug_btn.grid(row=1, column=3, sticky=tk.W, padx=5, pady=3)

    # 重新计算按钮（HDR）
    self.hdr_recalc_cct_btn = ttk.Button(
        self.hdr_cct_params_frame,
        text="应用新参数并重绘",
        command=self.recalculate_cct,
        bootstyle="success",
    )
    self.hdr_recalc_cct_btn.grid(
        row=4, column=0, columnspan=2, pady=10, padx=5, sticky="ew"
    )
    self.hdr_recalc_cct_btn.grid_remove()

    # 提示文字
    ttk.Label(
        self.hdr_cct_params_frame,
        text="提示: 清空输入框将恢复默认值",
        font=("SimHei", 8),
        foreground=_theme_colors()["muted"],
    ).grid(row=5, column=0, columnspan=4, sticky=tk.W, padx=5, pady=5)


def _get_cct_var_dict(self: "PQAutomationApp", test_type):
    """按测试类型返回 CCT 变量映射。"""
    if test_type == "sdr_movie":
        return {
            "x_ideal": self.sdr_cct_x_ideal_var,
            "x_tolerance": self.sdr_cct_x_tolerance_var,
            "y_ideal": self.sdr_cct_y_ideal_var,
            "y_tolerance": self.sdr_cct_y_tolerance_var,
        }
    if test_type == "hdr_movie":
        return {
            "x_ideal": self.hdr_cct_x_ideal_var,
            "x_tolerance": self.hdr_cct_x_tolerance_var,
            "y_ideal": self.hdr_cct_y_ideal_var,
            "y_tolerance": self.hdr_cct_y_tolerance_var,
        }
    return {
        "x_ideal": self.cct_x_ideal_var,
        "x_tolerance": self.cct_x_tolerance_var,
        "y_ideal": self.cct_y_ideal_var,
        "y_tolerance": self.cct_y_tolerance_var,
    }


def _parse_cct_float(self: "PQAutomationApp", var, default):
    """读取并解析 CCT 输入值，失败时回落默认值。"""
    try:
        value = var.get().strip()
        if value == "":
            return default
        return float(value)
    except Exception:
        return default


def _save_cct_params_for(self: "PQAutomationApp", test_type):
    """保存指定测试类型的 CCT 参数。"""
    try:
        default_params = self.config.get_default_cct_params(test_type)
        var_dict = _get_cct_var_dict(self, test_type)
        cct_params = {
            key: _parse_cct_float(self, var_dict[key], default_params[key])
            for key in default_params
        }

        if test_type not in self.config.current_test_types:
            self.config.current_test_types[test_type] = {}

        self.config.current_test_types[test_type]["cct_params"] = cct_params
        self.save_pq_config()
    except Exception:
        pass


def _handle_cct_focus_out(self: "PQAutomationApp", var, default_value, save_func, label):
    """统一处理 CCT 参数失焦校验并保存。"""
    try:
        value = var.get().strip()
        if value == "":
            var.set(str(default_value))
            if hasattr(self, "log_gui"):
                self.log_gui.log(f"{label} 参数为空，恢复默认值: {default_value}", level="success")
        else:
            try:
                float_val = float(value)
                if float_val < 0 or float_val > 1:
                    var.set(str(default_value))
                    if hasattr(self, "log_gui"):
                        self.log_gui.log(
                            f"{label} 参数超出范围，恢复默认值: {default_value}"
                        , level="error")
            except ValueError:
                var.set(str(default_value))
                if hasattr(self, "log_gui"):
                    self.log_gui.log(
                        f"{label} 参数无效，恢复默认值: {default_value}"
                    , level="error")

        save_func()
    except Exception as e:
        if hasattr(self, "log_gui"):
            self.log_gui.log(f"处理 {label} 参数失败: {str(e)}", level="error")


def on_sdr_cct_param_focus_out(self: "PQAutomationApp", var, default_value):
    """SDR 色度参数失去焦点时的处理。"""
    _handle_cct_focus_out(self, var, default_value, self.save_sdr_cct_params, "SDR")


def save_sdr_cct_params(self: "PQAutomationApp"):
    """保存 SDR 色度参数。"""
    _save_cct_params_for(self, "sdr_movie")


def on_hdr_cct_param_focus_out(self: "PQAutomationApp", var, default_value):
    """HDR 色度参数失去焦点时的处理。"""
    _handle_cct_focus_out(self, var, default_value, self.save_hdr_cct_params, "HDR")


def save_hdr_cct_params(self: "PQAutomationApp"):
    """保存 HDR 色度参数。"""
    _save_cct_params_for(self, "hdr_movie")


def recalculate_cct(self: "PQAutomationApp"):
    """重新计算并绘制色度图"""
    try:
        # 1. 保存新参数
        self.save_cct_params()
        self.log_gui.log("色度参数已更新", level="success")

        # 2. 收起配置项
        if hasattr(self, "config_panel_frame"):
            try:
                if self.config_panel_frame.winfo_viewable():
                    self.config_panel_frame.btn.invoke()
                    self.root.update_idletasks()
                    time.sleep(0.1)
            except:
                pass

        # 3. 跳转到色度图Tab
        self.chart_notebook.select(self.cct_chart_frame)
        self.root.update_idletasks()

        # 4. 检查是否有数据
        if not hasattr(self, "results") or not self.results:
            self.log_gui.log("没有测试数据，无法重新绘制", level="error")
            messagebox.showwarning("警告", "请先完成测试后再重新计算")
            return

        # 5. 获取保存的灰阶数据
        gray_data = self.results.get_intermediate_data("shared", "gray")
        if not gray_data:
            gray_data = self.results.get_intermediate_data("cct", "gray")

        if not gray_data or len(gray_data) < 2:
            self.log_gui.log("没有可用的灰阶数据", level="error")
            messagebox.showwarning("警告", "没有找到色度测试数据")
            return

        # 6. 重新计算 CCT
        self.log_gui.log("=" * 50, level="separator")
        self.log_gui.log("开始重新计算色度一致性...", level="info")
        self.log_gui.log("=" * 50, level="separator")

        cct_values = pq_algorithm.calculate_cct_from_results(gray_data)

        # 7. 更新结果
        self.results.set_test_item_result("cct", {"cct_values": cct_values})

        # 8. 重新绘制色度图
        test_type = self.config.current_test_type
        self.plot_cct(test_type)

        self.log_gui.log("色度图已重新绘制", level="success")
        self.log_gui.log("=" * 50, level="separator")

        messagebox.showinfo("成功", "色度图已根据新参数重新绘制！")

    except Exception as e:
        self.log_gui.log(f"重新计算失败: {str(e)}", level="error")
        self.log_gui.log(traceback.format_exc(), level="error")
        messagebox.showerror("错误", f"重新计算失败: {str(e)}")


def recalculate_gamut(self: "PQAutomationApp"):
    """重新计算并绘制色域图（使用新的参考标准）"""
    try:
        # 1. 收起配置项
        if hasattr(self, "config_panel_frame"):
            try:
                if self.config_panel_frame.winfo_viewable():
                    self.config_panel_frame.btn.invoke()
                    self.root.update_idletasks()
                    time.sleep(0.1)
            except:
                pass

        # 2. 跳转到色域图Tab
        self.chart_notebook.select(self.gamut_chart_frame)
        self.root.update_idletasks()

        # 3. 检查是否有数据
        if not hasattr(self, "results") or not self.results:
            self.log_gui.log("没有测试数据，无法重新绘制", level="error")
            messagebox.showwarning("警告", "请先完成测试后再重新计算")
            return

        # 4. 获取保存的色域数据
        rgb_data = self.results.get_intermediate_data("gamut", "rgb")

        if not rgb_data or len(rgb_data) < 3:
            self.log_gui.log("没有可用的色域数据", level="error")
            messagebox.showwarning("警告", "没有找到色域测试数据")
            return

        # 5. 获取当前测试类型
        test_type = self.config.current_test_type

        # 6. 获取用户选择的参考标准
        if test_type == "screen_module":
            reference_standard = self.screen_gamut_ref_var.get()
        elif test_type == "sdr_movie":
            reference_standard = self.sdr_gamut_ref_var.get()
        elif test_type == "hdr_movie":
            reference_standard = self.hdr_gamut_ref_var.get()
        else:
            reference_standard = "DCI-P3"

        self.log_gui.log("=" * 50, level="separator")
        self.log_gui.log(f"开始重新计算色域（参考标准: {reference_standard}）...", level="info")
        self.log_gui.log("=" * 50, level="separator")

        # 7. 重新计算 XY 色域覆盖率
        xy_points = [[result[0], result[1]] for result in rgb_data]

        # 根据参考标准计算 XY 覆盖率
        if reference_standard == "BT.2020":
            area_xy, coverage_xy = pq_algorithm.calculate_gamut_coverage_BT2020(
                xy_points
            )
        elif reference_standard == "BT.709":
            area_xy, coverage_xy = pq_algorithm.calculate_gamut_coverage_BT709(
                xy_points
            )
        elif reference_standard == "DCI-P3":
            area_xy, coverage_xy = pq_algorithm.calculate_gamut_coverage_DCIP3(
                xy_points
            )
        else:
            area_xy, coverage_xy = pq_algorithm.calculate_gamut_coverage_DCIP3(
                xy_points
            )
            reference_standard = "DCI-P3"

        self.log_gui.log(f"参考标准: {reference_standard}", level="success")
        self.log_gui.log(f"XY 色域覆盖率: {coverage_xy:.1f}%", level="success")

        # ========== ✅✅8. 重新计算 UV 色域覆盖率 ==========
        # 将 XY 坐标转换为 UV 坐标
        uv_points = []
        for x, y in xy_points:
            try:
                # XY转UV公式
                denom = -2 * x + 12 * y + 3
                if abs(denom) < 1e-10:
                    u, v = 0, 0
                else:
                    u = 4 * x / denom
                    v = 9 * y / denom
                uv_points.append([u, v])
            except ZeroDivisionError:
                continue

        self.log_gui.log(f"转换后的 UV 点数量: {len(uv_points)}", level="success")

        # 根据参考标准计算 UV 覆盖率
        if reference_standard == "BT.2020":
            area_uv, coverage_uv = pq_algorithm.calculate_gamut_coverage_BT2020_uv(
                uv_points
            )
        elif reference_standard == "BT.709":
            area_uv, coverage_uv = pq_algorithm.calculate_gamut_coverage_BT709_uv(
                uv_points
            )
        elif reference_standard == "DCI-P3":
            area_uv, coverage_uv = pq_algorithm.calculate_gamut_coverage_DCIP3_uv(
                uv_points
            )
        else:
            area_uv, coverage_uv = pq_algorithm.calculate_gamut_coverage_DCIP3_uv(
                uv_points
            )

        self.log_gui.log(f"UV 色域覆盖率: {coverage_uv:.1f}%", level="success")
        # ========================================================

        # 9. 更新结果（同时保存 XY 和 UV 覆盖率）
        self.results.set_test_item_result(
            "gamut",
            {
                "area": area_xy,  # ← 兼容旧字段
                "coverage": coverage_xy,  # ← 兼容旧字段
                "area_xy": area_xy,  # ← XY 面积
                "coverage_xy": coverage_xy,  # ← XY 覆盖率
                "area_uv": area_uv,  # ← UV 面积
                "coverage_uv": coverage_uv,  # ← UV 覆盖率
                "uv_coverage": coverage_uv,  # ← 兼容字段（Excel 导出用）
                "reference": reference_standard,
            },
        )

        self.log_gui.log("测试结果已更新到 results 对象", level="success")

        # 10. 重新绘制色域图
        self.plot_gamut(rgb_data, coverage_xy, test_type)

    except Exception as e:
        self.log_gui.log(f"重新计算失败: {str(e)}", level="error")
        self.log_gui.log(traceback.format_exc(), level="error")
        messagebox.showerror("错误", f"重新计算失败: {str(e)}")


def on_cct_param_focus_out(self: "PQAutomationApp", var, default_value):
    """色度参数失去焦点时的处理 - 空值恢复默认"""
    _handle_cct_focus_out(self, var, default_value, self.save_cct_params, "屏模组")


def save_cct_params(self: "PQAutomationApp"):
    """保存色度参数 - 简化版"""
    _save_cct_params_for(self, self.config.current_test_type)


def reload_cct_params(self: "PQAutomationApp"):
    """切换测试类型时重新加载色度参数"""
    try:
        current_type = self.config.current_test_type
        saved_params = self.config.current_test_types.get(current_type, {}).get(
            "cct_params", None
        )
        default_params = self.config.get_default_cct_params(current_type)

        if saved_params is None:
            saved_params = {}

        # 更新输入框的值
        if current_type == "screen_module":
            self.cct_x_ideal_var.set(
                str(saved_params["x_ideal"]) if "x_ideal" in saved_params else ""
            )
            self.cct_y_ideal_var.set(
                str(saved_params["y_ideal"]) if "y_ideal" in saved_params else ""
            )
        else:
            self.cct_x_ideal_var.set(str(saved_params.get("x_ideal", default_params["x_ideal"])) )
            self.cct_y_ideal_var.set(str(saved_params.get("y_ideal", default_params["y_ideal"])) )

        self.cct_x_tolerance_var.set(
            str(saved_params.get("x_tolerance", default_params["x_tolerance"]))
        )
        self.cct_y_tolerance_var.set(
            str(saved_params.get("y_tolerance", default_params["y_tolerance"]))
        )

    except Exception as e:
        if hasattr(self, "log_gui"):
            self.log_gui.log(f"重新加载色度参数失败: {str(e)}", level="error")


def toggle_cct_params_frame(self: "PQAutomationApp"):
    """根据测试类型和测试项的选中状态显示对应参数框"""
    selected_items = self.get_selected_test_items()
    current_test_type = self.config.current_test_type

    # ========== 默认隐藏所有参数框 ==========
    self.cct_params_frame.pack_forget()
    self.sdr_cct_params_frame.pack_forget()

    # HDR 色度参数框（如果存在的话）
    if hasattr(self, "hdr_cct_params_frame"):
        self.hdr_cct_params_frame.pack_forget()

    # ========== 根据测试类型和选中项显示对应参数框 ==========
    if current_test_type == "screen_module":
        # 屏模组：只有色度参数
        if "cct" in selected_items:
            self.cct_params_frame.pack(fill=tk.X, padx=5, pady=5)

    elif current_test_type == "sdr_movie":
        # SDR：只有色度参数（色准不需要参数设置框）
        if "cct" in selected_items:
            self.sdr_cct_params_frame.pack(fill=tk.X, padx=5, pady=5)

    elif current_test_type == "hdr_movie":
        # HDR：只有色度参数（色准不需要参数设置框）
        if "cct" in selected_items:
            if hasattr(self, "hdr_cct_params_frame"):
                self.hdr_cct_params_frame.pack(fill=tk.X, padx=5, pady=5)
            else:
                if hasattr(self, "log_gui"):
                    self.log_gui.log("HDR 色度参数框尚未创建", level="error")


# ---- gamut 参考标准改变回调（统一实现） ----
_GAMUT_REF_CONFIGS = {
    "screen_module": {"var_attr": "screen_gamut_ref_var", "label": "屏模组"},
    "sdr_movie": {"var_attr": "sdr_gamut_ref_var", "label": "SDR"},
    "hdr_movie": {"var_attr": "hdr_gamut_ref_var", "label": "HDR"},
}


def _on_gamut_ref_changed(self: "PQAutomationApp", test_type, event=None):
    cfg = _GAMUT_REF_CONFIGS[test_type]
    try:
        new_ref = getattr(self, cfg["var_attr"]).get()
        self.log_gui.log(f"{cfg['label']} 色域参考标准已更改为: {new_ref}", level="success")

        if test_type not in self.config.current_test_types:
            self.config.current_test_types[test_type] = {}
        self.config.current_test_types[test_type]["gamut_reference"] = new_ref
        self.save_pq_config()
    except Exception as e:
        self.log_gui.log(f"保存 {cfg['label']} 色域参考标准失败: {str(e)}", level="error")


def on_screen_gamut_ref_changed(self: "PQAutomationApp", event=None):
    _on_gamut_ref_changed(self, "screen_module", event)


def on_sdr_gamut_ref_changed(self: "PQAutomationApp", event=None):
    _on_gamut_ref_changed(self, "sdr_movie", event)


def on_hdr_gamut_ref_changed(self: "PQAutomationApp", event=None):
    _on_gamut_ref_changed(self, "hdr_movie", event)


class CctPanelMixin:
    """由 tools/refactor_to_mixins.py 自动生成。
    把本模块的自由函数挂到 PQAutomationApp 上，便于 F12 跳转与类型推断。
    """
    create_cct_params_frame = create_cct_params_frame
    _get_cct_var_dict = _get_cct_var_dict
    _parse_cct_float = _parse_cct_float
    _save_cct_params_for = _save_cct_params_for
    _handle_cct_focus_out = _handle_cct_focus_out
    on_sdr_cct_param_focus_out = on_sdr_cct_param_focus_out
    save_sdr_cct_params = save_sdr_cct_params
    on_hdr_cct_param_focus_out = on_hdr_cct_param_focus_out
    save_hdr_cct_params = save_hdr_cct_params
    recalculate_cct = recalculate_cct
    recalculate_gamut = recalculate_gamut
    on_cct_param_focus_out = on_cct_param_focus_out
    save_cct_params = save_cct_params
    reload_cct_params = reload_cct_params
    toggle_cct_params_frame = toggle_cct_params_frame
    _on_gamut_ref_changed = _on_gamut_ref_changed
    on_screen_gamut_ref_changed = on_screen_gamut_ref_changed
    on_sdr_gamut_ref_changed = on_sdr_gamut_ref_changed
    on_hdr_gamut_ref_changed = on_hdr_gamut_ref_changed
