from mimetypes import inited
from typing import Any

import tkinter as tk
from tkinter import ttk, messagebox
from datetime import datetime
import threading
import time
from core import constants
import core.eventbus as eBus
from core.logger import LogLevel, PrintLog
from core.sfgrid import bus_events
from core.sfgrid.model import SFGridTradeTarget
from core.qmt import qmtv
from core.sfgrid.sfgrid_strategy import SFGridStrategy


class TradeTargetUI(ttk.Frame):
    def __init__(self, parent):
        super().__init__(parent)
        self.tradeTargetData:dict[int, SFGridTradeTarget] = {} # id->trade_target
        self.stockCodeIdMap:dict[str, int] = {}
        self.strategy_ctrl:dict[int, SFGridStrategy] = {} # stock_code->trade_target
        self.listening_stock = []
        # 监控价格，默认值为10
        self.monitor_price = 10.0

        self.init_trade_target_pool()
        
        # 市场监控数据
        self.marketData: dict[str, Any] = {}  # 存储市场数据 {stock_code: {stock_name, last_price, time}}
        
        # 市场监控窗口显示状态
        self.market_monitor_visible = True
        
        # 创建界面
        self.create_ui()
        
        eBus.event_bus.subscribe(eBus.MarketDataUpdate, self.onMarketDataUpdated)
        eBus.event_bus.subscribe(bus_events.EventTradeTargetUpdate, self.onStrategyUpdate)
        eBus.event_bus.subscribe(bus_events.EventTradeTargetDeleted, self.onTradeTargetDeleted)
    

    def init_trade_target_pool(self):
        results = SFGridTradeTarget.select()
        for temp in results:
            tradeTarget:SFGridTradeTarget = temp
            tradeTarget.current_position = qmtv.getStockPosition(tradeTarget.stock_code) # type: ignore
            self.updateTradeTarget(tradeTarget, True) # 初始化的时候

        PrintLog(LogLevel.INFO, f'- [成功]交易标的信息初始化, 共 {len(self.tradeTargetData)} 个标的')

    
    # 收集所有市场数据用于市场监控
    def onMarketDataUpdated(self, data):
        for stock_code, tickData in data.items():
            if stock_code in self.stockCodeIdMap:
                id:int = self.stockCodeIdMap[stock_code]
                tradeTarget = self.tradeTargetData[id]
                PrintLog(LogLevel.INFO, f'|- 市价更新[{tradeTarget.targetName()}] - {id}市场数据更新=======================')
                lastPrice = float("{:.3f}".format(tickData['lastPrice']))    
                tradeTarget.market_price = lastPrice  # type: ignore
                self.updateTradeTarget(tradeTarget, False, True) # 市价更新
            else:
                # 非目标交易，发布市场数据更新事件用于市场监控
                lastPrice = tickData['lastPrice']
                # 使用用户设置的监控价格替代硬编码的10
                if lastPrice == self.monitor_price or stock_code in self.listening_stock:
                    # PrintLog(LogLevel.INFO, f'股票代码: {stock_code} 监听中, 市场数据更新 {tickData["lastPrice"]}')
                    # 发布市场数据更新事件用于市场监控
                    market_target = SFGridTradeTarget()
                    market_target.stock_code = stock_code
                    market_target.stock_name = qmtv.getInstrumentName(stock_code)  # type: ignore
                    market_target.market_price = lastPrice  # type: ignore
                    if stock_code not in self.listening_stock:
                        self.listening_stock.append(stock_code)
                    # 更新市场监控数据用于UI显示
                    current_time = datetime.now().strftime("%H:%M:%S")
                    self.marketData[str(stock_code)] = {
                        'stock_name': qmtv.getInstrumentName(stock_code),
                        'last_price': tickData['lastPrice'],
                        'time': current_time
                    }


    # 来自策略的数据更新
    def onStrategyUpdate(self, target: SFGridTradeTarget):
        id = target.get_id()
        self.tradeTargetData[id] = target


    # priceChange 用于控制是否对更新价格数据，进行交易判断
    def updateTradeTarget(self, target: SFGridTradeTarget, save: bool = True, priceChange:bool = False):
        if save:
            target.save()

        id = target.get_id()
        # PrintLog(LogLevel.INFO, f'  [序号-{id}] 股票代码: {target.stock_code}-{target.stock_name}: {target.plan_buy_price} {target.plan_sell_price}') # type: ignore
        # 更新或添加数据到本地缓存
        self.tradeTargetData[id] = target
            
        if id not in self.strategy_ctrl:
            self.stockCodeIdMap[target.stock_code] = id  # type: ignore
            self.strategy_ctrl[id] = SFGridStrategy(target)  # pyright: ignore[reportArgumentType]
        else:
            self.strategy_ctrl[id].updateTradeTarget(target)
            if priceChange:
                self.strategy_ctrl[id].onDataUpdate(target)

    # UI CREATE
    def create_ui(self):
        """创建UI界面"""
        # 主框架（使用self作为父容器）
        main_frame = ttk.Frame(self)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # 创建工具栏
        toolbar_frame = ttk.Frame(main_frame)
        toolbar_frame.pack(fill=tk.X, pady=(0, 10))
        
        # 工具栏按钮
        ttk.Button(toolbar_frame, text="➕ 添加标的", 
                  command=self.btnHandlerAddTradeTarget, width=12).pack(side=tk.LEFT, padx=2)
        ttk.Button(toolbar_frame, text="🗑 删除标的", 
                  command=self.btnHandlerDelSelectedTradeTarget, width=12).pack(side=tk.LEFT, padx=2)
        ttk.Button(toolbar_frame, text="▶️ 启动交易", 
                  command=self.btnHandlerStartSelectedTrade, width=12).pack(side=tk.LEFT, padx=2)
        ttk.Button(toolbar_frame, text="⏸ 暂停交易", 
                  command=self.btnHandlerStopSelectedTrade, width=12).pack(side=tk.LEFT, padx=2)
        ttk.Button(toolbar_frame, text="🛠 交易设置", 
                  command=self.btnHandlerTradeSettings, width=12).pack(side=tk.LEFT, padx=2)
        
        ttk.Button(toolbar_frame, text="▣ 边栏", 
                  command=self.btnHandlerToggleMarketMonitor, width=8).pack(side=tk.RIGHT, padx=2)
        # 添加价格监控输入字段和确认按钮
        ttk.Button(toolbar_frame, text="确认", 
                  command=self.btnHandlerSetMonitorPrice, width=8).pack(side=tk.RIGHT, padx=2)
        self.monitor_price_entry = ttk.Entry(toolbar_frame, width=8)
        self.monitor_price_entry.insert(0, str(self.monitor_price))
        self.monitor_price_entry.pack(side=tk.RIGHT, padx=2)
        ttk.Label(toolbar_frame, text="价格").pack(side=tk.RIGHT, padx=(20, 2))
        ttk.Label(toolbar_frame, text="监控配置").pack(side=tk.RIGHT, padx=(20, 2))
        
        # 表格区域
        self.create_tables_area(main_frame)

        # 启动刷新线程
        self.refresh_thread = threading.Thread(target=self.refresh_loop, daemon=True)
        self.refresh_thread.start()
        PrintLog(LogLevel.INFO, "UI刷新线程已启动")
    
    
    def refresh_loop(self):
        """刷新循环"""
        while True:
            self.after(0, self.refresh_table)
            self.after(0, self.populate_market_table)
            time.sleep(0.2)  # 每0.5秒刷新一次


    def create_tables_area(self, parent):
        """创建表格区域"""
        # 创建主表格框架（水平排列）
        tables_frame = ttk.Frame(parent)
        tables_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 5))
        
        # 左侧交易标的区域
        trade_frame = ttk.LabelFrame(tables_frame, text="交易标的详情", padding=10)
        trade_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 5))
        
        # 创建交易标的表格
        self.create_trade_target_table(trade_frame)
        
        # 右侧市场监控区域
        self.market_frame = ttk.LabelFrame(tables_frame, text="市场监控", padding=10)
        self.market_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=(5, 0))
        
        # 创建市场监控表格
        self.create_market_monitor_table(self.market_frame)

    
    def create_trade_target_table(self, parent):
        """创建交易标的表格"""
        
        columns = ("ID",
            "股票代码", "股票名称", "市场价", "持仓数量", 
            "最新成交价", "计划买入价", "计划卖出价", "当前订单价", "当前订单号", "当前订单类型", 
            "交易状态"
        )
        
        self.trade_table = ttk.Treeview(parent, columns=columns, show='headings', height=15)
        
        # 专业化的列配置
        column_configs = {
            "ID": (50, tk.CENTER),
            "股票代码": (90, tk.CENTER),
            "股票名称": (80, tk.E),
            "市场价": (70, tk.E),
            "持仓数量": (80, tk.E),
            "最新成交价": (90, tk.E),
            "计划买入价": (90, tk.E),
            "计划卖出价": (90, tk.E),
            "当前订单价": (90, tk.E),
            "当前订单号": (90, tk.E),
            "当前订单类型": (90, tk.E),
            "交易状态": (80, tk.CENTER)
        }
        
        for col in columns:
            width, anchor = column_configs[col]
            self.trade_table.heading(col, text=col)
            self.trade_table.column(col, width=width, anchor=anchor)  # type: ignore
        
        # 填充数据
        self.populate_trade_table()
        
        # 滚动条
        scrollbar = ttk.Scrollbar(parent, orient=tk.VERTICAL, command=self.trade_table.yview)
        self.trade_table.configure(yscrollcommand=scrollbar.set)
        
        self.trade_table.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 绑定双击事件
        self.trade_table.bind("<Double-1>", self.on_table_double_click)
    
    def create_market_monitor_table(self, parent):
        """创建市场监控表格"""
        columns = ("时间", "股票名称", "最新价格")
        
        self.market_table = ttk.Treeview(parent, columns=columns, show='headings', height=15)
        
        # 列配置
        column_configs = {
            "时间": (50, tk.CENTER),
            "股票名称": (80, tk.CENTER),
            "最新价格": (50, tk.CENTER)
        }
        
        for col in columns:
            width, anchor = column_configs[col]
            self.market_table.heading(col, text=col)
            self.market_table.column(col, width=width, anchor=anchor)  # type: ignore
        
        # 滚动条
        scrollbar = ttk.Scrollbar(parent, orient=tk.VERTICAL, command=self.market_table.yview)
        self.market_table.configure(yscrollcommand=scrollbar.set)
        
        self.market_table.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 绑定双击事件
        self.market_table.bind("<Double-1>", self.on_market_table_double_click)
        
        # 填充初始数据
        self.populate_market_table()
    
    def populate_market_table(self):
        """填充市场监控表格数据"""
        # 保存当前选中的项
        selected_items = self.market_table.selection()
        selected_values = []
        for item in selected_items:
            values = self.market_table.item(item)['values']
            if values:
                selected_values.append(values[1])  # 保存股票代码
        
        # 清空现有数据
        for item in self.market_table.get_children():
            self.market_table.delete(item)
        
        # 填充市场数据
        tmp = self.marketData.copy()
        for stock_code, data in tmp.items():
            # 处理时间格式，仅显示 hh:mm:ss
            time_str = data['time']
            # 如果时间字符串包含空格，说明包含日期和时间，只取时间部分
            if ' ' in time_str:
                time_str = time_str.split(' ')[1]
            
            # 确保时间格式为 hh:mm:ss，如果只有 hh:mm 则补充 :00
            if ':' in time_str:
                time_components = time_str.split(':')
                if len(time_components) == 2:
                    # 只有小时和分钟，补充秒
                    time_str = f"{time_components[0]}:{time_components[1]}:00"
                elif len(time_components) >= 3:
                    # 有小时、分钟和秒，只取前三个部分
                    time_str = f"{time_components[0]}:{time_components[1]}:{time_components[2]}"
            
            values = [
                time_str,
                data['stock_name']+f"{stock_code}",
                f"{data['last_price']:.3f}",
                stock_code
            ]
            self.market_table.insert('', tk.END, values=values)
        
        # 恢复之前选中的项
        if selected_values:
            for item in self.market_table.get_children():
                values = self.market_table.item(item)['values']
                if values and values[1] in selected_values:  # 比较股票代码
                    self.market_table.selection_add(item)
    
    def on_market_table_double_click(self, event):
        """市场监控表格双击事件"""
        selected = self.market_table.selection()
        if selected:
            item = selected[0]
            values = self.market_table.item(item)['values']
            print(values)
            stock_name = values[1]
            last_price = values[2]
            stock_code = values[3]
            
            # 检查是否已在交易池中
            is_in_trade_pool = any(target.stock_code == stock_code for target in self.tradeTargetData.values())
            
            if is_in_trade_pool:
                messagebox.showinfo("提示", f"{stock_code} ({stock_name}) 已在交易池中")
            else:
                result = messagebox.askyesno(
                    "添加交易标的",
                    f"确定要将以下股票添加到交易池吗？\n\n"
                    f"股票代码: {stock_code}\n"
                    f"股票名称: {stock_name}\n"
                    f"最新价格: {last_price}"
                )
                
                if result:
                    # 发布事件通知主控制器添加标的
                    self.addTradeTarget(stock_code)
    
    def get_trade_enabled_indicator(self, enabled: bool) -> str:
        """获取交易状态指示器"""
        if enabled:
            return "▶ 运行中"
        else:
            return "⏸ 已停止"
    
    def populate_trade_table(self):
        """填充交易标的表格数据"""
        for temp, target in self.tradeTargetData.items():
            if target.current_order_type == constants.OrderTypeBuy:
                orderTypeStr = "买"
            elif target.current_order_type == constants.OrderTypeSell:
                orderTypeStr = "卖"
            elif target.current_order_type == constants.OrderTypeInit:
                orderTypeStr = "建仓"
            else:
                orderTypeStr = "未知"
            values = [
                target.id,  # type: ignore                                                
                target.stock_code,
                target.stock_name,
                "-" if target.market_price is None else f"{target.market_price:.3f}",
                target.current_position,
                '-' if target.last_trade_price is None else f"{target.last_trade_price:.3f}",
                '-' if target.plan_buy_price is None else f"{target.plan_buy_price:.3f}",
                '-' if target.plan_sell_price is None else f"{target.plan_sell_price:.3f}",
                '-' if target.current_order_price is None else f"{target.current_order_price:.3f}",
                target.current_order_no,
                orderTypeStr,
                self.get_trade_enabled_indicator(target.enabled)  # type: ignore
            ]
            
            self.trade_table.insert('', tk.END, values=values)

    
    def get_status_text(self, status):
        """获取状态文本"""
        status_map = {
            0: "新标的",
            1: "交易中"
        }
        return status_map.get(status, "未知")
    
    def on_table_double_click(self, event):
        """表格双击事件"""
        selected = self.trade_table.selection()
        if selected:
            item = selected[0]
            values = self.trade_table.item(item)['values']
            PrintLog(LogLevel.DEBUG, f"双击查看详情: {values[0]} - {values[1]}")
    
    def get_selected_target(self):
        """获取选中的交易标的"""
        selected = self.trade_table.selection()
        if not selected:
            messagebox.showwarning("未选中", "请先选择一个交易标的")
            return None
        
        # 获取选中行的ID
        item = selected[0]
        values = self.trade_table.item(item)['values']
        target_id = values[0]
        
        # 从列表中找到对应的target对象
        for id in self.tradeTargetData:
            if int(target_id) == id:  # type: ignore
                return self.tradeTargetData[id]
        
        return None
    
    def refresh_table(self):
        """刷新表格数据"""
        # 保存当前选中的项
        selected_items = self.trade_table.selection()
        selected_values = []
        for item in selected_items:
            values = self.trade_table.item(item)['values']
            if values:
                selected_values.append(values[0])  # 保存ID
        
        # 清空表格
        for item in self.trade_table.get_children():
            self.trade_table.delete(item)
        
        # 重新填充
        self.populate_trade_table()
        
        # 恢复之前选中的项
        if selected_values:
            for item in self.trade_table.get_children():
                values = self.trade_table.item(item)['values']
                if values and values[0] in selected_values:
                    self.trade_table.selection_add(item)
        
        # 刷新市场监控表格
        self.populate_market_table()
    
    def create_grid_view_window(self, target: SFGridTradeTarget):
        """创建网格配置查看窗口（只读）"""
        # 获取顶层窗口
        root = self.winfo_toplevel()
        
        # 创建顶层窗口
        view_window = tk.Toplevel(root)
        view_window.title(f"网格配置查看 - {target.stock_code} ({target.stock_name})")
        view_window.geometry("500x450")
        view_window.resizable(False, False)
        
        # 设置窗口模态
        view_window.transient(root)
        view_window.grab_set()
        
        # 居中显示
        root.update_idletasks()
        x = root.winfo_x() + (root.winfo_width() // 2) - 250
        y = root.winfo_y() + (root.winfo_height() // 2) - 225
        view_window.geometry(f"500x450+{x}+{y}")
        
        # 创建主框架
        main_frame = ttk.Frame(view_window, padding=20)
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 显示股票信息
        info_frame = ttk.LabelFrame(main_frame, text="标的详情", padding=10)
        info_frame.pack(fill=tk.X, pady=(0, 10))
        
        ttk.Label(info_frame, text=f"股票代码: {target.stock_code}").grid(row=0, column=0, sticky=tk.W, pady=2)
        ttk.Label(info_frame, text=f"股票名称: {target.stock_name}").grid(row=0, column=1, sticky=tk.W, padx=(20, 0), pady=2)
        ttk.Label(info_frame, text=f"状态: 已建初始仓（仅查看模式）").grid(row=1, column=0, columnspan=2, sticky=tk.W, pady=2)
        
        # 创建网格配置查看框架
        config_frame = ttk.LabelFrame(main_frame, text="网格配置", padding=10)
        config_frame.pack(fill=tk.X, pady=(0, 10))
        
        # 基准价格
        base_price_frame = ttk.Frame(config_frame)
        base_price_frame.pack(fill=tk.X, pady=5)
        ttk.Label(base_price_frame, text="基准价格:", width=15).pack(side=tk.LEFT)
        ttk.Label(base_price_frame, text=f"{target.grid_start_price:.3f}", width=15, anchor=tk.W).pack(side=tk.LEFT, padx=5)
        ttk.Label(base_price_frame, text="元", foreground='gray').pack(side=tk.LEFT)
        
        # 网格大小
        grid_size_frame = ttk.Frame(config_frame)
        grid_size_frame.pack(fill=tk.X, pady=5)
        ttk.Label(grid_size_frame, text="网格大小:", width=15).pack(side=tk.LEFT)
        ttk.Label(grid_size_frame, text=f"{target.grid_size:.3f}", width=15, anchor=tk.W).pack(side=tk.LEFT, padx=5)
        ttk.Label(grid_size_frame, text="元", foreground='gray').pack(side=tk.LEFT)
        
        # 网格交易量
        grid_volume_frame = ttk.Frame(config_frame)
        grid_volume_frame.pack(fill=tk.X, pady=5)
        ttk.Label(grid_volume_frame, text="网格交易量:", width=15).pack(side=tk.LEFT)
        ttk.Label(grid_volume_frame, text=str(target.grid_volume), width=15, anchor=tk.W).pack(side=tk.LEFT, padx=5)
        ttk.Label(grid_volume_frame, text="股", foreground='gray').pack(side=tk.LEFT)
        
        # 上方网格数量
        upper_count_frame = ttk.Frame(config_frame)
        upper_count_frame.pack(fill=tk.X, pady=5)
        ttk.Label(upper_count_frame, text="上方网格数量:", width=15).pack(side=tk.LEFT)
        ttk.Label(upper_count_frame, text=str(target.grid_upper_count), width=15, anchor=tk.W).pack(side=tk.LEFT, padx=5)
        ttk.Label(upper_count_frame, text="格", foreground='gray').pack(side=tk.LEFT)
        
        # 下方网格数量
        lower_count_frame = ttk.Frame(config_frame)
        lower_count_frame.pack(fill=tk.X, pady=5)
        ttk.Label(lower_count_frame, text="下方网格数量:", width=15).pack(side=tk.LEFT)
        ttk.Label(lower_count_frame, text=str(target.grid_lower_count), width=15, anchor=tk.W).pack(side=tk.LEFT, padx=5)
        ttk.Label(lower_count_frame, text="格", foreground='gray').pack(side=tk.LEFT)
        
        # 生成网格价格序列
        price_grid_frame = ttk.LabelFrame(main_frame, text="网格价格序列", padding=10)
        price_grid_frame.pack(fill=tk.X, pady=(0, 10))
        
        # 计算并显示网格价格序列
        price_list = target.getPriceGrid()
        price_text = ", ".join([f"{price:.3f}" for price in price_list])
        
        # 创建文本框显示网格价格序列
        text_frame = ttk.Frame(price_grid_frame)
        text_frame.pack(fill=tk.BOTH, expand=True)
        
        text_widget = tk.Text(text_frame, height=4, wrap=tk.WORD)
        text_widget.insert(tk.END, price_text)
        text_widget.config(state=tk.DISABLED)  # 只读
        
        scrollbar = ttk.Scrollbar(text_frame, orient=tk.VERTICAL, command=text_widget.yview)
        text_widget.configure(yscrollcommand=scrollbar.set)
        
        text_widget.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 关闭按钮
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(fill=tk.X, pady=(10, 0))
        ttk.Button(button_frame, text="关闭", command=view_window.destroy).pack(side=tk.RIGHT, padx=5)
    
    def create_grid_config_window(self, target: SFGridTradeTarget):
        """创建网格配置窗口（可编辑）"""
        # 获取顶层窗口
        root = self.winfo_toplevel()
        
        # 创建顶层窗口
        config_window = tk.Toplevel(root)
        config_window.title(f"网格配置 - {target.stock_code} ({target.stock_name})")
        config_window.geometry("550x550")
        config_window.resizable(False, False)
        
        # 设置窗口模态
        config_window.transient(root)
        config_window.grab_set()
        
        # 居中显示
        root.update_idletasks()
        x = root.winfo_x() + (root.winfo_width() // 2) - 275
        y = root.winfo_y() + (root.winfo_height() // 2) - 275
        config_window.geometry(f"550x550+{x}+{y}")
        
        # 创建主框架
        main_frame = ttk.Frame(config_window, padding=20)
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 显示股票信息
        info_frame = ttk.LabelFrame(main_frame, text="标的详情", padding=10)
        info_frame.pack(fill=tk.X, pady=(0, 10))
        
        ttk.Label(info_frame, text=f"股票代码: {target.stock_code}").grid(row=0, column=0, sticky=tk.W, pady=2)
        ttk.Label(info_frame, text=f"股票名称: {target.stock_name}").grid(row=0, column=1, sticky=tk.W, padx=(20, 0), pady=2)
        ttk.Label(info_frame, text=f"状态: 新标的（可配置模式）").grid(row=1, column=0, columnspan=2, sticky=tk.W, pady=2)
        
        # 创建网格配置框架
        config_frame = ttk.LabelFrame(main_frame, text="网格配置", padding=15)
        config_frame.pack(fill=tk.X, pady=(0, 10))
        
        # 创建输入框字典用于保存引用
        entries = {}
        
        # 基准价格
        base_price_frame = ttk.Frame(config_frame)
        base_price_frame.pack(fill=tk.X, pady=5)
        ttk.Label(base_price_frame, text="基准价格:", width=15).pack(side=tk.LEFT)
        base_price_entry = ttk.Entry(base_price_frame, width=15)
        base_price_entry.insert(0, str(target.grid_start_price))
        base_price_entry.pack(side=tk.LEFT, padx=5)
        ttk.Label(base_price_frame, text="元", foreground='gray').pack(side=tk.LEFT)
        entries['grid_start_price'] = base_price_entry
        
        # 网格大小
        grid_size_frame = ttk.Frame(config_frame)
        grid_size_frame.pack(fill=tk.X, pady=5)
        ttk.Label(grid_size_frame, text="网格大小:", width=15).pack(side=tk.LEFT)
        grid_size_entry = ttk.Entry(grid_size_frame, width=15)
        grid_size_entry.insert(0, str(target.grid_size))
        grid_size_entry.pack(side=tk.LEFT, padx=5)
        ttk.Label(grid_size_frame, text="元", foreground='gray').pack(side=tk.LEFT)
        entries['grid_size'] = grid_size_entry
        
        # 网格交易量
        grid_volume_frame = ttk.Frame(config_frame)
        grid_volume_frame.pack(fill=tk.X, pady=5)
        ttk.Label(grid_volume_frame, text="网格交易量:", width=15).pack(side=tk.LEFT)
        grid_volume_entry = ttk.Entry(grid_volume_frame, width=15)
        grid_volume_entry.insert(0, str(target.grid_volume))
        grid_volume_entry.pack(side=tk.LEFT, padx=5)
        ttk.Label(grid_volume_frame, text="手", foreground='gray').pack(side=tk.LEFT)
        entries['grid_volume'] = grid_volume_entry
        
        # 上方网格数量
        upper_count_frame = ttk.Frame(config_frame)
        upper_count_frame.pack(fill=tk.X, pady=5)
        ttk.Label(upper_count_frame, text="上方网格数量:", width=15).pack(side=tk.LEFT)
        upper_count_entry = ttk.Entry(upper_count_frame, width=15)
        upper_count_entry.insert(0, str(target.grid_upper_count))
        upper_count_entry.pack(side=tk.LEFT, padx=5)
        ttk.Label(upper_count_frame, text="格", foreground='gray').pack(side=tk.LEFT)
        entries['grid_upper_count'] = upper_count_entry
        
        # 下方网格数量
        lower_count_frame = ttk.Frame(config_frame)
        lower_count_frame.pack(fill=tk.X, pady=5)
        ttk.Label(lower_count_frame, text="下方网格数量:", width=15).pack(side=tk.LEFT)
        lower_count_entry = ttk.Entry(lower_count_frame, width=15)
        lower_count_entry.insert(0, str(target.grid_lower_count))
        lower_count_entry.pack(side=tk.LEFT, padx=5)
        ttk.Label(lower_count_frame, text="格", foreground='gray').pack(side=tk.LEFT)
        entries['grid_lower_count'] = lower_count_entry
        
        # 预览按钮和结果显示
        preview_frame = ttk.LabelFrame(main_frame, text="网格价格序列预览", padding=10)
        preview_frame.pack(fill=tk.X, pady=(0, 10))
        
        preview_result = tk.StringVar(value="点击'预览'查看生成的网格价格序列")
        
        def calculate_grid_prices():
            """计算网格价格序列"""
            try:
                base_price = float(base_price_entry.get())
                grid_size = float(grid_size_entry.get())
                upper_count = int(upper_count_entry.get())
                lower_count = int(lower_count_entry.get())
                
                prices = []
                
                # 计算上方网格价格
                for i in range(upper_count, 0, -1):
                    price = base_price + grid_size * i
                    prices.append(round(price, 3))
                
                # 添加基准价格
                prices.append(base_price)
                
                # 计算下方网格价格
                for i in range(1, lower_count + 1):
                    price = base_price - grid_size * i
                    # 确保价格不为负
                    if price >= 0:
                        prices.append(round(price, 3))
                    else:
                        break
                
                return prices
            except ValueError:
                return None
        
        def update_preview():
            """更新网格价格序列预览"""
            prices = calculate_grid_prices()
            if prices:
                price_str = ", ".join([str(p) for p in prices])
                preview_result.set(f"网格价格序列: {price_str}")
            else:
                preview_result.set("参数错误，请检查输入！")
        
        # 绑定输入变化自动预览
        for entry_widget in entries.values():
            entry_widget.bind("<KeyRelease>", lambda e: update_preview())
            entry_widget.bind("<FocusOut>", lambda e: update_preview())
        
        # 预览按钮
        preview_button_frame = ttk.Frame(preview_frame)
        preview_button_frame.pack(fill=tk.X, pady=5)
        # ttk.Button(preview_button_frame, text="预览", command=update_preview).pack(side=tk.LEFT)
        
        # 预览结果显示
        preview_label = ttk.Label(preview_button_frame, textvariable=preview_result, foreground='blue')
        preview_label.pack(side=tk.LEFT, padx=10)
        
        # 初始预览
        update_preview()
        
        # 按钮框架
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(fill=tk.X, pady=(10, 0))
        
        def save_config():
            """保存配置"""
            try:
                # 获取输入值
                grid_start_price = float(base_price_entry.get())
                grid_size = float(grid_size_entry.get())
                grid_volume = int(grid_volume_entry.get())
                grid_upper_count = int(upper_count_entry.get())
                grid_lower_count = int(lower_count_entry.get())
                
                # 更新target对象（使用setattr来正确设置Peewee字段的值）
                setattr(target, 'grid_start_price', grid_start_price)
                setattr(target, 'grid_size', grid_size)
                setattr(target, 'grid_volume', grid_volume)
                setattr(target, 'grid_upper_count', grid_upper_count)
                setattr(target, 'grid_lower_count', grid_lower_count)
                setattr(target, 'status', 0)
                
                # 更新策略控制器
                self.updateTradeTarget(target, True) # 网格配置变更
                
                # 关闭窗口
                config_window.destroy()
                
                # 添加日志
                PrintLog(LogLevel.INFO, f"网格配置已保存: {target.stock_code} - {target.stock_name}")
                messagebox.showinfo("成功", "网格配置已保存！")
                
            except ValueError:
                messagebox.showerror("错误", "输入参数有误，请检查！")
            except Exception as e:
                messagebox.showerror("错误", f"保存配置失败：{str(e)}")
                PrintLog(LogLevel.ERROR, f"保存网格配置失败: {str(e)}")
        
        # 保存和取消按钮
        ttk.Button(button_frame, text="保存", command=save_config).pack(side=tk.RIGHT, padx=5)
        ttk.Button(button_frame, text="取消", command=config_window.destroy).pack(side=tk.RIGHT, padx=5)
    
    def decrease_grid_index(self, grid_index_var: tk.IntVar, target: SFGridTradeTarget, required_position_label: ttk.Label, position_status_label: ttk.Label):
        """减少网格序号"""
        current_value = grid_index_var.get()
        if current_value > 0:
            grid_index_var.set(current_value - 1)
            # 同步更新需求持仓量和持仓状态
            self.update_required_position_and_status(grid_index_var.get(), target, required_position_label, position_status_label)
    
    def increase_grid_index(self, grid_index_var: tk.IntVar, max_index: int, target: SFGridTradeTarget, required_position_label: ttk.Label, position_status_label: ttk.Label):
        """增加网格序号"""
        current_value = grid_index_var.get()
        if current_value < max_index:
            grid_index_var.set(current_value + 1)
            # 同步更新需求持仓量和持仓状态
            self.update_required_position_and_status(grid_index_var.get(), target, required_position_label, position_status_label)


    def create_grid_correction_window(self, target: SFGridTradeTarget):
        """创建网格修正窗口"""
        # 获取顶层窗口
        root = self.winfo_toplevel()
        
        # 创建顶层窗口
        correction_window = tk.Toplevel(root)
        correction_window.title(f"网格修正 - {target.stock_code} ({target.stock_name})")
        correction_window.geometry("500x400")
        correction_window.resizable(False, False)
        
        # 设置窗口模态
        correction_window.transient(root)
        correction_window.grab_set()
        
        # 居中显示
        root.update_idletasks()
        x = root.winfo_x() + (root.winfo_width() // 2) - 250
        y = root.winfo_y() + (root.winfo_height() // 2) - 200
        correction_window.geometry(f"500x400+{x}+{y}")
        
        # 创建主框架
        main_frame = ttk.Frame(correction_window, padding=20)
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 显示股票信息
        info_frame = ttk.LabelFrame(main_frame, text="标的详情", padding=10)
        info_frame.pack(fill=tk.X, pady=(0, 10))
        
        ttk.Label(info_frame, text=f"股票代码: {target.stock_code}").grid(row=0, column=0, sticky=tk.W, pady=2)
        ttk.Label(info_frame, text=f"股票名称: {target.stock_name}").grid(row=0, column=1, sticky=tk.W, padx=(20, 0), pady=2)
        
        # 创建修正选项框架
        options_frame = ttk.LabelFrame(main_frame, text="修正选项", padding=10)
        options_frame.pack(fill=tk.X, pady=(0, 10))
        
        # 网格序号
        grid_index_frame = ttk.Frame(options_frame)
        grid_index_frame.pack(fill=tk.X, pady=5)
        
        ttk.Label(grid_index_frame, text="网格序号:", width=12).pack(side=tk.LEFT)
        
        # 网格序号调整控件
        grid_index_var = tk.IntVar(value=getattr(target, 'grid_index'))
        
        # 当前持仓量
        position_frame = ttk.Frame(options_frame)
        position_frame.pack(fill=tk.X, pady=5)
        
        current_position_value = getattr(target, 'current_position')
        ttk.Label(position_frame, text="当前持仓量:", width=12).pack(side=tk.LEFT)
        ttk.Label(position_frame, text=str(current_position_value), width=10, anchor=tk.CENTER).pack(side=tk.LEFT, padx=5)
        
        # 需求持仓量
        required_position_frame = ttk.Frame(options_frame)
        required_position_frame.pack(fill=tk.X, pady=5)
        
        grid_index_value = getattr(target, 'grid_index')
        required_position = grid_index_value * target.grid_volume
        ttk.Label(required_position_frame, text="需求持仓量:", width=12).pack(side=tk.LEFT)
        required_position_label = ttk.Label(required_position_frame, text=str(required_position), width=10, anchor=tk.CENTER)
        required_position_label.pack(side=tk.LEFT, padx=5)
        
        # 持仓量状态提示
        position_status_frame = ttk.Frame(options_frame)
        position_status_frame.pack(fill=tk.X, pady=5)
        
        position_status_label = ttk.Label(position_status_frame, text="", foreground="red")
        position_status_label.pack(side=tk.LEFT, padx=(12, 0))
        
        # 初始化持仓量状态
        self.update_position_status(current_position_value, required_position, position_status_label)
        
        # 网格序号显示和按钮
        grid_index_label = ttk.Label(grid_index_frame, textvariable=grid_index_var, width=10, anchor=tk.CENTER)
        grid_index_label.pack(side=tk.LEFT, padx=5)
        
        # 减少按钮
        ttk.Button(grid_index_frame, text="-", width=3, 
                  command=lambda: self.decrease_grid_index(grid_index_var, target, required_position_label, position_status_label)).pack(side=tk.LEFT, padx=(5, 5))
        
        # 增加按钮
        ttk.Button(grid_index_frame, text="+", width=3, 
                  command=lambda: self.increase_grid_index(grid_index_var, len(target.getPriceGrid())-1, target, required_position_label, position_status_label)).pack(side=tk.LEFT, padx=(5, 0))
        
        # 当前价格（实时更新）
        price_frame = ttk.Frame(options_frame)
        price_frame.pack(fill=tk.X, pady=5)
        
        ttk.Label(price_frame, text="当前价格:", width=12).pack(side=tk.LEFT)
        current_price_var = tk.StringVar(value="-")
        current_price_label = ttk.Label(price_frame, textvariable=current_price_var, width=10, anchor=tk.CENTER)
        current_price_label.pack(side=tk.LEFT, padx=5)
        
        # 保存按钮框架
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(fill=tk.X, pady=(10, 0))
        
        # 保存按钮
        ttk.Button(button_frame, text="确认修正", 
                  command=lambda: self.save_grid_correction(correction_window, target, grid_index_var.get())).pack(side=tk.RIGHT, padx=5)
        
        # 取消按钮
        ttk.Button(button_frame, text="取消", 
                  command=correction_window.destroy).pack(side=tk.RIGHT, padx=5)
        
        # 监听市场数据更新
        def on_market_data_update(updated_target: SFGridTradeTarget):
            if updated_target.get_id() == target.get_id():
                current_price_var.set(f"{updated_target.market_price:.3f}" if updated_target.market_price else "-")
        
        # 订阅市场数据更新事件
        eBus.event_bus.subscribe(eBus.MarketDataUpdate, on_market_data_update)
        
        # 窗口关闭时取消订阅
        def on_window_close():
            if eBus.MarketDataUpdate in eBus.event_bus.listeners and on_market_data_update in eBus.event_bus.listeners[eBus.MarketDataUpdate]:
                eBus.event_bus.listeners[eBus.MarketDataUpdate].remove(on_market_data_update)
            correction_window.destroy()
        
        correction_window.protocol("WM_DELETE_WINDOW", on_window_close)
        
        # 初始化当前价格
        if target.market_price is not None:
            current_price_var.set(f"{target.market_price:.3f}")
    
    def update_position_status(self, current_position: int, required_position: int, status_label: ttk.Label):
        """更新持仓量状态提示"""
        if current_position >= required_position:
            status_label.config(text="持仓量充足", foreground="green")
        else:
            shortage = required_position - current_position
            status_label.config(text=f"还需补充 {shortage} 手仓位", foreground="red")
    
    def save_grid_correction(self, window, target: SFGridTradeTarget, new_grid_index: int):
        """保存网格修正"""
        # 更新网格序号
        setattr(target, 'grid_index', new_grid_index)
        
        # 重新计算需求持仓量
        required_position = new_grid_index * target.grid_volume
        
        # 检查持仓量是否满足要求
        current_position = getattr(target, 'current_position')
        if current_position < required_position:
            shortage = required_position - current_position
            result = messagebox.askyesno(
                "持仓量不足",
                f"当前持仓量({current_position}手)小于需求持仓量({required_position}手)\n"
                f"还需补充 {shortage} 手仓位，是否继续保存？"
            )
            if not result:
                return
        
        # 关闭窗口
        window.destroy()
        
        # 添加日志
        PrintLog(LogLevel.INFO, f"网格修正已保存: {target.stock_code} - {target.stock_name}, 网格序号: {new_grid_index}")

    
    def update_required_position_and_status(self, grid_index: int, target: SFGridTradeTarget, required_position_label: ttk.Label, position_status_label: ttk.Label):
        """更新需求持仓量和持仓状态"""
        # 计算需求持仓量
        required_position:int = grid_index * target.grid_volume # type: ignore
        required_position_label.config(text=str(required_position))
        
        # 更新持仓量状态
        current_position = getattr(target, 'current_position')
        self.update_position_status(current_position, required_position, position_status_label)
    
    
    # 交易池管理
    def addTradeTarget(self, stock_code: str, gridIndex: int = 1):    # 新增
        """处理添加交易标的事件"""
        try:
            stock_name = qmtv.getInstrumentName(stock_code)
            if not stock_name:
                PrintLog(LogLevel.ERROR, f'无法获取股票代码 {stock_code} 的名称，请检查代码是否正确')
                return
            PrintLog(LogLevel.DEBUG, f'添加交易标的: {stock_code} {stock_name}')
            
            # 检查是否已存在该标的
            existing_target = SFGridTradeTarget.get_or_none(SFGridTradeTarget.stock_code == stock_code)
            if existing_target:
                PrintLog(LogLevel.INFO, f'交易标的 {stock_code} {stock_name} 已存在')
                return
            
            # 刷新标的持仓
            pos = qmtv.getStockPosition(stock_code) # type: ignore
            new_target = SFGridTradeTarget.create(
                stock_name=stock_name,
                stock_code=stock_code,
                market_price=0.0,
                current_position=pos,
                grid_index=gridIndex,
                last_trade_price=0.0,
                plan_buy_price=0.0,
                plan_sell_price=0.0,
                current_order_price=0.0,
                current_order_no='',
                current_order_type='',
                status=-1
            )
            # 更新标的池
            self.updateTradeTarget(new_target, True) # 新增标的，相当于也是初始化
            
        except Exception as e:
            PrintLog(LogLevel.ERROR, f'新增交易标的失败 {stock_code} {e}')

    # button handlers =============================================================================================
    def btnHandlerGridCorrect(self):
        
        target = self.get_selected_target()
        if not target:
            return
        self.create_grid_correction_window(target)
    

    def btnHandlerToggleMarketMonitor(self):
        """切换市场监控窗口显示/隐藏"""
        if self.market_monitor_visible:
            # 隐藏市场监控窗口
            self.market_frame.pack_forget()
            self.market_monitor_visible = False
        else:
            # 显示市场监控窗口
            self.market_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=(5, 0))
            self.market_monitor_visible = True

    def btnHandlerTradeSettings(self):
        """网格配置功能"""
        target = self.get_selected_target()
        if not target:
            return
        
        # 检查标的的状态，status为1时仅可查看
        if target.status == -1 or target.status == 0:
            self.create_grid_config_window(target)
        else:
            # 创建只读的网格配置查看窗口
            self.create_grid_view_window(target)

    def btnHandlerStartSelectedTrade(self):
        """启动选中的交易"""
        target = self.get_selected_target()
        if not target:
            return
        
        if target.enabled:  # type: ignore
            messagebox.showinfo("提示", f"{target.stock_code} ({target.stock_name}) 已经在运行中")
            return
        
        result = messagebox.askyesno(
            "确认启动",
            f"确定要启动以下交易标的吗？\n\n"
            f"股票代码: {target.stock_code}\n"
            f"股票名称: {target.stock_name}"
        )
        
        if result:
            PrintLog(LogLevel.INFO, f'启动标的交易 {target.targetName()}')
            target.enabled = True  # type: ignore
    
            id =  target.get_id()
            if id in self.strategy_ctrl:
                tradeController: SFGridStrategy = self.strategy_ctrl[target.get_id()]
                tradeTarget = tradeController.enabledTrading(True)
                self.tradeTargetData[id] = tradeTarget
            else:
                PrintLog(LogLevel.INFO, f"\t创建标的交易控制器 {target.targetName()}")
    
    def btnHandlerStopSelectedTrade(self):
        """暂停选中的交易"""
        target = self.get_selected_target()
        if not target:
            return
        
        if not target.enabled:  # type: ignore
            messagebox.showinfo("提示", f"{target.stock_code} ({target.stock_name}) 已经是暂停状态")
            return
        
        result = messagebox.askyesno(
            "确认暂停",
            f"确定要暂停以下交易标的吗？\n\n"
            f"股票代码: {target.stock_code}\n"
            f"股票名称: {target.stock_name}"
        )
        
        if result:
            PrintLog(LogLevel.INFO, f'暂停标的交易 {target.targetName()}')
            id =  target.get_id()
            if id in self.strategy_ctrl:
                tradeController: SFGridStrategy = self.strategy_ctrl[target.get_id()]
                tradeController.enabledTrading(False)
            else:
                print(f"标的交易控制器不存在 {target.stock_code} {target.stock_name}\n")
    
    def btnHandlerDelSelectedTradeTarget(self):
        """删除选中的交易标的"""
        target = self.get_selected_target()
        if not target:
            return
        
        result = messagebox.askyesno(
            "确认删除",
            f"确定要删除以下交易标的吗？\n\n"
            f"股票代码: {target.stock_code}\n"
            f"股票名称: {target.stock_name}\n\n"
            f"⚠️ 此操作不可恢复！",
            icon='warning'
        )
        
        if result:
            id = target.get_id()
            # try:
            ctrl = self.strategy_ctrl[id]
            ctrl.deleteTradeTarget(target)
            PrintLog(LogLevel.INFO, f"已发送删除请求: {target.stock_code} - {target.stock_name}")
    
    def onTradeTargetDeleted(self, target: SFGridTradeTarget):
        id = target.get_id()
        del self.tradeTargetData[id]
        del self.strategy_ctrl[id]
        del self.stockCodeIdMap[target.stock_code] # type: ignore

    def btnHandlerAddTradeTarget(self):
        """添加新的交易标的"""
        # 获取顶层窗口
        root = self.winfo_toplevel()
        
        # 创建顶层窗口
        add_window = tk.Toplevel(root)
        add_window.title("添加交易标的")
        add_window.geometry("400x150")
        add_window.resizable(False, False)
        
        # 设置窗口模态
        add_window.transient(root)
        add_window.grab_set()
        
        # 居中显示
        root.update_idletasks()
        x = root.winfo_x() + (root.winfo_width() // 2) - 200
        y = root.winfo_y() + (root.winfo_height() // 2) - 75
        add_window.geometry(f"400x150+{x}+{y}")
        
        # 创建输入框架
        input_frame = ttk.Frame(add_window, padding=20)
        input_frame.pack(fill=tk.BOTH, expand=True)
        
        # 股票代码输入
        ttk.Label(input_frame, text="股票代码:").grid(row=0, column=0, sticky=tk.W, pady=5)
        stock_code_entry = ttk.Entry(input_frame, width=30)
        stock_code_entry.grid(row=0, column=1, pady=5, padx=(10, 0))
        stock_code_entry.focus()
        
        # 按钮框架
        button_frame = ttk.Frame(input_frame)
        button_frame.grid(row=1, column=0, columnspan=2, pady=20)
        
        def confirm_add():
            stock_code = stock_code_entry.get().strip()
            if not stock_code:
                messagebox.showwarning("输入错误", "请输入股票代码")
                return
            
            # 发布事件通知主控制器添加标的
            self.addTradeTarget(stock_code)
            add_window.destroy()
        
        def cancel_add():
            add_window.destroy()
        
        # 确认和取消按钮
        ttk.Button(button_frame, text="确认", command=confirm_add, width=10).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="取消", command=cancel_add, width=10).pack(side=tk.LEFT, padx=5)
        
        # 绑定回车键确认
        stock_code_entry.bind('<Return>', lambda event: confirm_add())
        
        PrintLog(LogLevel.INFO, "点击添加交易标的按钮")
    
    def btnHandlerSetMonitorPrice(self):
        """设置监控价格"""
        try:
            # 获取输入的价格
            price_str = self.monitor_price_entry.get()
            new_price = float(price_str)
            
            # 更新监控价格
            self.monitor_price = new_price
            
            # 清空当前监控的数据
            self.marketData.clear()
            self.listening_stock.clear()
            
            # 清空市场监控表格
            for item in self.market_table.get_children():
                self.market_table.delete(item)
                
            PrintLog(LogLevel.INFO, f"监控价格已更新为: {new_price}")
        except ValueError:
            messagebox.showerror("错误", "请输入有效的数字")
