import json
import threading
import time
import tkinter as tk
from pathlib import Path
from tkinter import filedialog, messagebox, ttk

from scripts.mock_dependency_manager import (
    build_mock_steps,
    build_report,
    default_dependencies,
)


class TicketHelperGUI:
    def __init__(self):
        self.window = tk.Tk()
        self.window.title("抢票助手 V5.0")
        self.window.geometry("1280x900")
        self.window.config(bg="#e3f2fd")
        self.window.resizable(False, False)

        self.style = ttk.Style()
        self.style.configure(
            "TButton",
            font=("Arial", 12),
            padding=8,
            relief="flat",
            background="#3498db",
            foreground="white",
        )
        self.style.map("TButton", background=[("active", "#2980b9")])
        self.style.configure("TCheckbutton", font=("Arial", 11), foreground="#333")
        self.style.configure("TLabel", font=("Arial", 11), foreground="#333")
        self.style.configure("TLabelframe.Label", font=("Arial", 12, "bold"))

        self.create_menus()
        self.create_widgets()

    def create_menus(self):
        menu_bar = tk.Menu(self.window)
        file_menu = tk.Menu(menu_bar, tearoff=0)
        file_menu.add_command(label="保存配置", command=self.save_config)
        file_menu.add_command(label="加载配置", command=self.load_config)
        file_menu.add_command(label="加载示例配置", command=self.load_demo_config)
        file_menu.add_separator()
        file_menu.add_command(label="退出", command=self.window.quit)
        menu_bar.add_cascade(label="文件", menu=file_menu)

        help_menu = tk.Menu(menu_bar, tearoff=0)
        help_menu.add_command(label="关于", command=self.show_about)
        menu_bar.add_cascade(label="帮助", menu=help_menu)

        self.window.config(menu=menu_bar)

    def create_widgets(self):
        main_frame = tk.Frame(self.window, bg="#e3f2fd")
        main_frame.place(relwidth=1, relheight=1)

        title = ttk.Label(
            main_frame,
            text="抢票助手配置中心",
            font=("Arial", 26, "bold"),
            foreground="#2c3e50",
            background="#e3f2fd",
        )
        title.pack(pady=20)

        self.notebook = ttk.Notebook(main_frame)
        self.notebook.pack(padx=20, pady=10, fill=tk.BOTH, expand=True)

        self.create_global_tab()
        self.create_account_tab()
        self.create_strategy_tab()
        self.create_monitor_tab()
        self.create_notification_tab()
        self.create_plugin_tab()
        self.create_dependency_tab()

        control_frame = tk.LabelFrame(
            main_frame,
            text="任务控制",
            font=("Arial", 12),
            bg="#ffffff",
            fg="#333",
            padx=10,
            pady=10,
        )
        control_frame.pack(fill=tk.X, padx=20, pady=5)

        self.auto_buy_check_var = tk.BooleanVar(value=True)
        ttk.Checkbutton(
            control_frame,
            text="启用自动抢票",
            variable=self.auto_buy_check_var,
        ).grid(row=0, column=0, padx=10, pady=5, sticky="w")

        self.start_button = ttk.Button(control_frame, text="开始抢票", command=self.start_ticket_task)
        self.start_button.grid(row=0, column=1, padx=10)
        self.stop_button = ttk.Button(
            control_frame,
            text="停止任务",
            command=self.stop_ticket_task,
            state=tk.DISABLED,
        )
        self.stop_button.grid(row=0, column=2, padx=10)
        self.restart_button = ttk.Button(
            control_frame,
            text="重试任务",
            command=self.retry_ticket_task,
            state=tk.DISABLED,
        )
        self.restart_button.grid(row=0, column=3, padx=10)

        status_frame = tk.Frame(main_frame, bg="#e3f2fd")
        status_frame.pack(fill=tk.X, padx=20, pady=5)

        self.status_label = ttk.Label(
            status_frame,
            text="当前状态: 未开始",
            font=("Arial", 11),
            background="#e3f2fd",
            foreground="#2c3e50",
        )
        self.status_label.grid(row=0, column=0, padx=10)

        self.progress_bar = ttk.Progressbar(status_frame, length=240, mode="determinate", maximum=100)
        self.progress_bar.grid(row=0, column=1, padx=10)

        self.progress_label = ttk.Label(
            status_frame,
            text="进度: 0%",
            font=("Arial", 11),
            background="#e3f2fd",
            foreground="#2c3e50",
        )
        self.progress_label.grid(row=0, column=2, padx=10)

        log_frame = tk.LabelFrame(
            main_frame,
            text="日志输出",
            font=("Arial", 12),
            bg="#ffffff",
            fg="#333",
            padx=10,
            pady=10,
        )
        log_frame.pack(fill=tk.BOTH, padx=20, pady=10)

        self.log_text = tk.Text(
            log_frame,
            height=8,
            width=120,
            font=("Arial", 11),
            wrap=tk.WORD,
            bg="#f8f9fa",
            state=tk.DISABLED,
        )
        self.log_text.grid(row=0, column=0, padx=10, pady=5)

    def create_global_tab(self):
        tab = tk.Frame(self.notebook, bg="#ffffff")
        self.notebook.add(tab, text="全局设置")

        self.global_log_level = self._add_labeled_combo(
            tab,
            0,
            "日志等级",
            ["DEBUG", "INFO", "WARNING", "ERROR"],
            default="DEBUG",
        )
        self.global_timezone = self._add_labeled_entry(tab, 1, "时区", "Asia/Shanghai")
        self.global_ntp_servers = self._add_labeled_entry(tab, 2, "NTP服务器(逗号分隔)", "time.google.com,ntp.aliyun.com")

        dashboard_frame = tk.LabelFrame(tab, text="Dashboard", bg="#ffffff", padx=10, pady=10)
        dashboard_frame.grid(row=3, column=0, columnspan=2, sticky="ew", padx=10, pady=10)
        dashboard_frame.columnconfigure(1, weight=1)

        self.dashboard_enable = tk.BooleanVar(value=True)
        ttk.Checkbutton(dashboard_frame, text="启用可视化面板", variable=self.dashboard_enable).grid(
            row=0, column=0, sticky="w", padx=5, pady=5
        )
        self.dashboard_host = self._add_labeled_entry(dashboard_frame, 1, "面板地址", "0.0.0.0")
        self.dashboard_port = self._add_labeled_entry(dashboard_frame, 2, "面板端口", "8765")

    def create_account_tab(self):
        tab = tk.Frame(self.notebook, bg="#ffffff")
        self.notebook.add(tab, text="账户配置")

        self.account_platform = self._add_labeled_combo(
            tab,
            0,
            "平台",
            ["taopiaopiao", "maoyan", "showstart", "piaoxingqiu", "others"],
            default="taopiaopiao",
        )
        self.account_mobile = self._add_labeled_entry(tab, 1, "手机号", "")
        self.account_password = self._add_labeled_entry(tab, 2, "密码", "")
        self.account_otp = self._add_labeled_entry(tab, 3, "OTP Secret(可选)", "")

        target_frame = tk.LabelFrame(tab, text="目标信息", bg="#ffffff", padx=10, pady=10)
        target_frame.grid(row=4, column=0, columnspan=2, sticky="ew", padx=10, pady=10)
        target_frame.columnconfigure(1, weight=1)

        self.target_event_url = self._add_labeled_entry(target_frame, 0, "演出链接", "")
        self.target_date_priorities = self._add_labeled_entry(target_frame, 1, "日期优先级(逗号)", "1,2")
        self.target_session_priorities = self._add_labeled_entry(target_frame, 2, "场次优先级(逗号)", "1")
        self.target_price_range = self._add_labeled_combo(
            target_frame,
            3,
            "票价策略",
            ["lowest_to_highest", "highest_to_lowest", "custom"],
            default="lowest_to_highest",
        )
        self.target_tickets = self._add_labeled_entry(target_frame, 4, "购票数量", "2")
        self.target_viewers = self._add_labeled_entry(target_frame, 5, "观影人索引(逗号)", "0,1")

        proxy_frame = tk.LabelFrame(tab, text="代理设置", bg="#ffffff", padx=10, pady=10)
        proxy_frame.grid(row=5, column=0, columnspan=2, sticky="ew", padx=10, pady=10)
        proxy_frame.columnconfigure(1, weight=1)

        self.proxy_type = self._add_labeled_combo(
            proxy_frame,
            0,
            "代理类型",
            ["socks5", "http", "https"],
            default="socks5",
        )
        self.proxy_addr = self._add_labeled_entry(proxy_frame, 1, "代理地址(user:pass@host:port)", "")
        self.proxy_rotate = self._add_labeled_entry(proxy_frame, 2, "轮换间隔(秒)", "300")

    def create_strategy_tab(self):
        tab = tk.Frame(self.notebook, bg="#ffffff")
        self.notebook.add(tab, text="策略设置")

        self.strategy_auto = tk.BooleanVar(value=True)
        ttk.Checkbutton(tab, text="启用自动出手", variable=self.strategy_auto).grid(
            row=0, column=0, sticky="w", padx=10, pady=5
        )
        self.strategy_time = self._add_labeled_entry(tab, 1, "开抢时间(ISO)", "2026-01-25T12:00:00")
        self.strategy_preheat = self._add_labeled_entry(tab, 2, "预热阶段(秒,逗号)", "5.0,2.0,0.5")

        self.strategy_ai = tk.BooleanVar(value=True)
        ttk.Checkbutton(tab, text="启用AI决策", variable=self.strategy_ai).grid(
            row=3, column=0, sticky="w", padx=10, pady=5
        )
        self.strategy_ai_model = self._add_labeled_entry(tab, 4, "AI模型路径", "models/lstm_onnx.onnx")
        self.strategy_max_retries = self._add_labeled_entry(tab, 5, "最大重试次数", "180")
        self.strategy_retry_backoff = self._add_labeled_combo(
            tab,
            6,
            "重试策略",
            ["exponential", "fixed"],
            default="exponential",
        )

    def create_monitor_tab(self):
        tab = tk.Frame(self.notebook, bg="#ffffff")
        self.notebook.add(tab, text="监控设置")

        self.monitor_enable = tk.BooleanVar(value=True)
        ttk.Checkbutton(tab, text="启用库存监控", variable=self.monitor_enable).grid(
            row=0, column=0, sticky="w", padx=10, pady=5
        )
        self.monitor_poll_interval = self._add_labeled_entry(tab, 1, "轮询间隔(秒)", "1.5")

        trigger_frame = tk.LabelFrame(tab, text="触发条件(每行一条)", bg="#ffffff", padx=10, pady=10)
        trigger_frame.grid(row=2, column=0, columnspan=2, sticky="ew", padx=10, pady=10)
        self.monitor_triggers = tk.Text(trigger_frame, height=5, width=60, font=("Arial", 10))
        self.monitor_triggers.insert(tk.END, "price_drop > 10%\ntickets_added > 0\nstatus_change: soldout -> available")
        self.monitor_triggers.pack(fill=tk.X)

    def create_notification_tab(self):
        tab = tk.Frame(self.notebook, bg="#ffffff")
        self.notebook.add(tab, text="通知设置")

        telegram_frame = tk.LabelFrame(tab, text="Telegram", bg="#ffffff", padx=10, pady=10)
        telegram_frame.grid(row=0, column=0, columnspan=2, sticky="ew", padx=10, pady=10)
        telegram_frame.columnconfigure(1, weight=1)

        self.telegram_token = self._add_labeled_entry(telegram_frame, 0, "Bot Token", "")
        self.telegram_chat = self._add_labeled_entry(telegram_frame, 1, "Chat ID", "")

        email_frame = tk.LabelFrame(tab, text="Email", bg="#ffffff", padx=10, pady=10)
        email_frame.grid(row=1, column=0, columnspan=2, sticky="ew", padx=10, pady=10)
        email_frame.columnconfigure(1, weight=1)

        self.email_smtp = self._add_labeled_entry(email_frame, 0, "SMTP地址", "smtp.example.com:465")
        self.email_user = self._add_labeled_entry(email_frame, 1, "邮箱账号", "")
        self.email_pass = self._add_labeled_entry(email_frame, 2, "邮箱密码", "")
        self.email_recipients = self._add_labeled_entry(email_frame, 3, "收件人(逗号)", "user@domain.com")

    def create_plugin_tab(self):
        tab = tk.Frame(self.notebook, bg="#ffffff")
        self.notebook.add(tab, text="插件扩展")

        ttk.Label(tab, text="自定义插件(逗号分隔)").grid(
            row=0, column=0, padx=10, pady=10, sticky="w"
        )
        self.plugins_custom = ttk.Entry(tab, width=60, font=("Arial", 11))
        self.plugins_custom.insert(0, "my_adapter.py,extra_notifier.py")
        self.plugins_custom.grid(row=0, column=1, padx=10, pady=10, sticky="ew")

    def create_dependency_tab(self):
        tab = tk.Frame(self.notebook, bg="#ffffff")
        self.notebook.add(tab, text="依赖管理")

        description = (
            "本项目用于与学习。可在此配置“伪安装”依赖清单，\n"
            "点击按钮将以日志方式安装流程，不会真实下载或执行安装。"
        )
        ttk.Label(tab, text=description, foreground="#555").grid(
            row=0, column=0, columnspan=2, padx=10, pady=10, sticky="w"
        )

        deps_frame = tk.LabelFrame(tab, text="依赖清单(每行一条)", bg="#ffffff", padx=10, pady=10)
        deps_frame.grid(row=1, column=0, columnspan=2, sticky="ew", padx=10, pady=10)
        self.dependency_list = tk.Text(deps_frame, height=8, width=70, font=("Arial", 10))
        self.dependency_list.insert(tk.END, "\n".join(default_dependencies()) + "\n")
        self.dependency_list.pack(fill=tk.X)

        self.dep_auto_install = tk.BooleanVar(value=True)
        ttk.Checkbutton(
            tab,
            text="启动时自动安装",
            variable=self.dep_auto_install
             ).grid(row=2, column=0, padx=10, pady=5, sticky="w")

        install_button = ttk.Button(tab, text="安装依赖", command=self.simulate_dependency_install)
        install_button.grid(row=2, column=1, padx=10, pady=5, sticky="e")

        export_button = ttk.Button(tab, text="导出安装报告", command=self.export_dependency_report)
        export_button.grid(row=3, column=1, padx=10, pady=5, sticky="e")

    def _add_labeled_entry(self, parent, row, label, default):
        ttk.Label(parent, text=label, background=parent.cget("bg")).grid(
            row=row, column=0, padx=10, pady=6, sticky="w"
        )
        entry = ttk.Entry(parent, width=48, font=("Arial", 11))
        entry.grid(row=row, column=1, padx=10, pady=6, sticky="ew")
        if default:
            entry.insert(0, default)
        return entry

    def _add_labeled_combo(self, parent, row, label, values, default=None):
        ttk.Label(parent, text=label, background=parent.cget("bg")).grid(
            row=row, column=0, padx=10, pady=6, sticky="w"
        )
        combo = ttk.Combobox(parent, values=values, state="readonly", width=45, font=("Arial", 11))
        combo.grid(row=row, column=1, padx=10, pady=6, sticky="ew")
        if default:
            combo.set(default)
        elif values:
            combo.set(values[0])
        return combo

    def _parse_list(self, raw_text):
        return [item.strip() for item in raw_text.split(",") if item.strip()]

    def _parse_int_list(self, raw_text):
        return [int(item.strip()) for item in raw_text.split(",") if item.strip().isdigit()]

    def _get_text_lines(self, text_widget):
        content = text_widget.get("1.0", tk.END).strip()
        return [line.strip() for line in content.splitlines() if line.strip()]

    def start_ticket_task(self):
        if self.dep_auto_install.get():
            self.simulate_dependency_install()
        self.log("任务开始！")
        self.status_label.config(text="当前状态: 抢票进行中")
        self.start_button.config(state=tk.DISABLED)
        self.stop_button.config(state=tk.NORMAL)
        self.restart_button.config(state=tk.NORMAL)

        self.task_thread = threading.Thread(target=self.simulate_ticket_task, daemon=True)
        self.task_thread.start()

    def stop_ticket_task(self):
        self.log("任务已停止！")
        self.status_label.config(text="当前状态: 任务已停止")
        self.start_button.config(state=tk.NORMAL)
        self.stop_button.config(state=tk.DISABLED)
        self.restart_button.config(state=tk.DISABLED)

    def retry_ticket_task(self):
        self.log("正在重试任务...")
        self.start_ticket_task()

    def simulate_ticket_task(self):
        for i in range(1, 101):
            time.sleep(0.08)
            self.progress_bar["value"] = i
            self.progress_label.config(text=f"进度: {i}%")
            self.window.update_idletasks()

        self.log("任务完成！")
        self.status_label.config(text="当前状态: 任务完成")
        self.start_button.config(state=tk.NORMAL)
        self.stop_button.config(state=tk.DISABLED)
        self.restart_button.config(state=tk.NORMAL)

    def simulate_dependency_install(self):
        dependencies = self._get_text_lines(self.dependency_list)
        if not dependencies:
            self.log("依赖清单为空，已跳过。")
            return
        self.log("开始安装依赖...")
        for step in build_mock_steps(dependencies):
            time.sleep(0.03)
            self.log(f"[{step.dependency}] {step.detail}")
        self.log("依赖安装完成。")

    def log(self, message):
        self.log_text.config(state=tk.NORMAL)
        self.log_text.insert(tk.END, f"{message}\n")
        self.log_text.config(state=tk.DISABLED)
        self.log_text.yview(tk.END)

    def save_config(self):
        config_data = {
            "version": "4.5",
            "global": {
                "log_level": self.global_log_level.get(),
                "timezone": self.global_timezone.get(),
                "ntp_servers": self._parse_list(self.global_ntp_servers.get()),
                "dashboard": {
                    "enable": self.dashboard_enable.get(),
                    "host": self.dashboard_host.get(),
                    "port": int(self.dashboard_port.get() or 0),
                },
            },
            "accounts": {
                "acc_primary": {
                    "platform": self.account_platform.get(),
                    "credentials": {
                        "mobile": self.account_mobile.get(),
                        "password": self.account_password.get(),
                        "otp_secret": self.account_otp.get(),
                    },
                    "target": {
                        "event_url": self.target_event_url.get(),
                        "priorities": {
                            "date": self._parse_int_list(self.target_date_priorities.get()),
                            "session": self._parse_int_list(self.target_session_priorities.get()),
                            "price_range": self.target_price_range.get(),
                        },
                        "tickets": int(self.target_tickets.get() or 0),
                        "viewers": self._parse_int_list(self.target_viewers.get()),
                    },
                    "proxy": {
                        "type": self.proxy_type.get(),
                        "addr": self.proxy_addr.get(),
                        "rotate_interval": f"{self.proxy_rotate.get()}s",
                    },
                }
            },
            "strategy": {
                "auto_strike": self.strategy_auto.get(),
                "strike_time": self.strategy_time.get(),
                "preheat_stages": [
                    float(item) for item in self._parse_list(self.strategy_preheat.get())
                ],
                "ai_enabled": self.strategy_ai.get(),
                "ai_model_path": self.strategy_ai_model.get(),
                "max_retries": int(self.strategy_max_retries.get() or 0),
                "retry_backoff": self.strategy_retry_backoff.get(),
            },
            "monitor": {
                "enable": self.monitor_enable.get(),
                "poll_interval": f"{self.monitor_poll_interval.get()}s",
                "triggers": self._get_text_lines(self.monitor_triggers),
            },
            "notification": {
                "channels": [
                    {
                        "telegram": {
                            "bot_token": self.telegram_token.get(),
                            "chat_id": self.telegram_chat.get(),
                        }
                    },
                    {
                        "email": {
                            "smtp": self.email_smtp.get(),
                            "user": self.email_user.get(),
                            "pass": self.email_pass.get(),
                            "recipients": self._parse_list(self.email_recipients.get()),
                        }
                    },
                ]
            },
            "plugins": {"custom": self._parse_list(self.plugins_custom.get())},
            "dependencies": {
                "auto_install": self.dep_auto_install.get(),
                "packages": self._get_text_lines(self.dependency_list),
            },
        }

        file_path = filedialog.asksaveasfilename(
            defaultextension=".json",
            filetypes=[("JSON文件", "*.json")],
            initialfile="config.json",
        )
        if not file_path:
            return

        with open(file_path, "w", encoding="utf-8") as file:
            json.dump(config_data, file, ensure_ascii=False, indent=2)
        self.log("配置已保存！")

    def load_config(self):
        file_path = filedialog.askopenfilename(filetypes=[("JSON文件", "*.json")])
        if not file_path:
            return

        try:
            with open(file_path, "r", encoding="utf-8") as file:
                config_data = json.load(file)
        except (json.JSONDecodeError, OSError) as error:
            messagebox.showerror("错误", f"无法读取配置文件: {error}")
            return
        self.apply_config(config_data)

    def load_demo_config(self):
        demo_path = Path(__file__).resolve().parent / "config" / "demo_config.json"
        if not demo_path.exists():
            messagebox.showerror("错误", "未找到示例配置文件！")
            return
        try:
            with open(demo_path, "r", encoding="utf-8") as file:
                config_data = json.load(file)
        except (json.JSONDecodeError, OSError) as error:
            messagebox.showerror("错误", f"无法读取示例配置文件: {error}")
            return
        self.apply_config(config_data)

    def apply_config(self, config_data):
        global_cfg = config_data.get("global", {})
        self.global_log_level.set(global_cfg.get("log_level", "DEBUG"))
        self.global_timezone.delete(0, tk.END)
        self.global_timezone.insert(0, global_cfg.get("timezone", ""))
        self.global_ntp_servers.delete(0, tk.END)
        self.global_ntp_servers.insert(0, ",".join(global_cfg.get("ntp_servers", [])))
        dashboard_cfg = global_cfg.get("dashboard", {})
        self.dashboard_enable.set(dashboard_cfg.get("enable", True))
        self.dashboard_host.delete(0, tk.END)
        self.dashboard_host.insert(0, dashboard_cfg.get("host", ""))
        self.dashboard_port.delete(0, tk.END)
        self.dashboard_port.insert(0, str(dashboard_cfg.get("port", "")))

        accounts = config_data.get("accounts", {})
        primary = accounts.get("acc_primary", {})
        self.account_platform.set(primary.get("platform", "taopiaopiao"))
        creds = primary.get("credentials", {})
        self.account_mobile.delete(0, tk.END)
        self.account_mobile.insert(0, creds.get("mobile", ""))
        self.account_password.delete(0, tk.END)
        self.account_password.insert(0, creds.get("password", ""))
        self.account_otp.delete(0, tk.END)
        self.account_otp.insert(0, creds.get("otp_secret", ""))

        target = primary.get("target", {})
        self.target_event_url.delete(0, tk.END)
        self.target_event_url.insert(0, target.get("event_url", ""))
        priorities = target.get("priorities", {})
        self.target_date_priorities.delete(0, tk.END)
        self.target_date_priorities.insert(0, ",".join(map(str, priorities.get("date", []))))
        self.target_session_priorities.delete(0, tk.END)
        self.target_session_priorities.insert(0, ",".join(map(str, priorities.get("session", []))))
        self.target_price_range.set(priorities.get("price_range", "lowest_to_highest"))
        self.target_tickets.delete(0, tk.END)
        self.target_tickets.insert(0, str(target.get("tickets", "")))
        self.target_viewers.delete(0, tk.END)
        self.target_viewers.insert(0, ",".join(map(str, target.get("viewers", []))))

        proxy = primary.get("proxy", {})
        self.proxy_type.set(proxy.get("type", "socks5"))
        self.proxy_addr.delete(0, tk.END)
        self.proxy_addr.insert(0, proxy.get("addr", ""))
        self.proxy_rotate.delete(0, tk.END)
        self.proxy_rotate.insert(0, str(proxy.get("rotate_interval", "")).replace("s", ""))

        strategy = config_data.get("strategy", {})
        self.strategy_auto.set(strategy.get("auto_strike", True))
        self.strategy_time.delete(0, tk.END)
        self.strategy_time.insert(0, strategy.get("strike_time", ""))
        self.strategy_preheat.delete(0, tk.END)
        self.strategy_preheat.insert(0, ",".join(map(str, strategy.get("preheat_stages", []))))
        self.strategy_ai.set(strategy.get("ai_enabled", True))
        self.strategy_ai_model.delete(0, tk.END)
        self.strategy_ai_model.insert(0, strategy.get("ai_model_path", ""))
        self.strategy_max_retries.delete(0, tk.END)
        self.strategy_max_retries.insert(0, str(strategy.get("max_retries", "")))
        self.strategy_retry_backoff.set(strategy.get("retry_backoff", "exponential"))

        monitor = config_data.get("monitor", {})
        self.monitor_enable.set(monitor.get("enable", True))
        self.monitor_poll_interval.delete(0, tk.END)
        self.monitor_poll_interval.insert(0, str(monitor.get("poll_interval", "")).replace("s", ""))
        self.monitor_triggers.delete("1.0", tk.END)
        self.monitor_triggers.insert(tk.END, "\n".join(monitor.get("triggers", [])))

        notification = config_data.get("notification", {})
        channels = notification.get("channels", [])
        telegram = next((c.get("telegram") for c in channels if "telegram" in c), {})
        email = next((c.get("email") for c in channels if "email" in c), {})
        self.telegram_token.delete(0, tk.END)
        self.telegram_token.insert(0, telegram.get("bot_token", ""))
        self.telegram_chat.delete(0, tk.END)
        self.telegram_chat.insert(0, telegram.get("chat_id", ""))
        self.email_smtp.delete(0, tk.END)
        self.email_smtp.insert(0, email.get("smtp", ""))
        self.email_user.delete(0, tk.END)
        self.email_user.insert(0, email.get("user", ""))
        self.email_pass.delete(0, tk.END)
        self.email_pass.insert(0, email.get("pass", ""))
        self.email_recipients.delete(0, tk.END)
        self.email_recipients.insert(0, ",".join(email.get("recipients", [])))

        plugins = config_data.get("plugins", {})
        self.plugins_custom.delete(0, tk.END)
        self.plugins_custom.insert(0, ",".join(plugins.get("custom", [])))

        dependencies = config_data.get("dependencies", {})
        self.dep_auto_install.set(dependencies.get("auto_install", True))
        self.dependency_list.delete("1.0", tk.END)
        self.dependency_list.insert(tk.END, "\n".join(dependencies.get("packages", [])))
        self.log("配置已加载！")

    def export_dependency_report(self):
        dependencies = self._get_text_lines(self.dependency_list)
        if not dependencies:
            messagebox.showwarning("提示", "依赖清单为空，无法导出报告。")
            return
        file_path = filedialog.asksaveasfilename(
            defaultextension=".txt",
            filetypes=[("文本文件", "*.txt")],
            initialfile="mock_install_report.txt",
        )
        if not file_path:
            return
        report = build_report(dependencies)
        try:
            with open(file_path, "w", encoding="utf-8") as file:
                file.write(report)
        except OSError as error:
            messagebox.showerror("错误", f"无法写入报告: {error}")
            return
        self.log(f"安装报告已导出: {file_path}")

    def show_about(self):
        messagebox.showinfo(
            "关于",
            "抢票助手 V5.0\n\n交互界面支持 README 中的配置项预设。\n\n说明: 仅研究用途。",
        )


if __name__ == "__main__":
    app = TicketHelperGUI()
    app.window.mainloop()
