# coding:utf-8
import pymysql
import logging
import datetime
import time
from typing import Dict, List, Optional, Tuple
from dbutils.pooled_db import PooledDB  # 1. 引入 PooledDB
from config_loader import get_database_config

# --- 连接池的配置 ---
# 2. 创建全局唯一的数据库连接池
# 我们可以把连接池看作一个"连接的仓库"，所有线程都从这里借用和归还连接
try:
    db_config = get_database_config()
    pool = PooledDB(
        creator=pymysql,  # 指定使用 pymysql 作为数据库连接库
        mincached=2,      # 初始化时，池中至少创建的空闲连接数
        maxcached=5,      # 池中最多能存放的空闲连接数
        maxconnections=10, # 连接池允许的最大连接数
        blocking=True,    # 连接池中无可用连接时，是否阻塞等待
        host=db_config['host'],
        port=db_config['port'],
        user=db_config['user'],
        password=db_config['password'],
        database=db_config['database'],
        charset='utf8mb4',
        autocommit=True,  # 注意：这里设置 autocommit=True，每次执行完 SQL 会自动提交
        # 连接保活配置
        connect_timeout=10,
        read_timeout=60,
        write_timeout=60
    )
    # 获取一个初始化日志记录器
    initial_logger = logging.getLogger(__name__)
    initial_logger.info("数据库连接池创建成功")
except Exception as e:
    initial_logger = logging.getLogger(__name__)
    initial_logger.error(f"数据库连接池创建失败: {str(e)}")
    pool = None # 创建失败，则 pool 为 None

def close_pool():
    """关闭连接池（在应用退出时调用）"""
    if pool:
        pool.close()
        logging.getLogger(__name__).info("数据库连接池已关闭")

class DatabaseManager:
    """
    数据库管理器类（已改造为使用连接池）
    现在这个类的每个实例都是轻量级的，并且线程安全。
    """
    
    def __init__(self, logger=None):
        self.logger = logger or logging.getLogger(__name__)
        if pool is None:
            raise Exception("数据库连接池未初始化，请检查配置")
        # 3. 每个实例共享同一个连接池
        self.pool = pool
    
    def _get_connection(self):
        """从连接池获取一个连接"""
        return self.pool.connection()

    def execute_query(self, sql: str, params: tuple = None) -> List[Tuple]:
        """执行查询SQL（从连接池获取连接）"""
        # 4. 每次执行都从池中获取一个新连接，用完后自动归还
        conn = self._get_connection()
        try:
            with conn.cursor() as cursor:
                cursor.execute(sql, params)
                result = cursor.fetchall()
                return result
        except Exception as e:
            self.logger.error(f"执行查询失败: {sql}, 错误: {str(e)}")
            # 连接池会自动处理坏掉的连接，所以通常不需要复杂的重连逻辑
            raise
        finally:
            if conn:
                # 5. conn.close() 在这里不是关闭连接，而是将连接【归还】给连接池
                conn.close()
    
    def execute_update(self, sql: str, params: tuple = None) -> int:
        """执行更新SQL（从连接池获取连接）"""
        conn = self._get_connection()
        try:
            with conn.cursor() as cursor:
                affected_rows = cursor.execute(sql, params)
                # 因为设置了 autocommit=True, 所以不需要手动 conn.commit()
                return affected_rows
        except Exception as e:
            self.logger.error(f"执行更新失败: {sql}, 错误: {str(e)}")
            raise
        finally:
            if conn:
                # 同样，将连接归还给池
                conn.close()
    
    # ======================================================================
    #  注意：以下所有业务逻辑方法，都不需要做任何修改！
    #  因为它们都依赖于 execute_query 和 execute_update，而这两个方法已经被改造好了。
    # ======================================================================

    def get_active_buy_plans(self, strategy_id: int = 1) -> Dict[str, Dict]:
        """获取激活的买入计划（仅当日最新记录）"""
        sql = """
        SELECT t.stock_code, t.stock_name, t.target_price, t.buy_amount, t.trading_version
        FROM trading_buy_plan t
        JOIN (
          SELECT stock_code, MAX(update_time) AS max_ut
          FROM trading_buy_plan
          WHERE strategy_id=%s AND is_active=1 AND DATE(trading_time)=CURDATE()
          GROUP BY stock_code
        ) m ON t.stock_code=m.stock_code AND t.update_time=m.max_ut
        WHERE t.strategy_id=%s AND t.is_active=1
        """
        try:
            results = self.execute_query(sql, (strategy_id, strategy_id))
            buy_plans = {}
            for row in results:
                stock_code, stock_name, target_price, buy_amount, tver = row
                buy_plans[stock_code] = {
                    'stock_name': stock_name,
                    'target_price': float(target_price),
                    'buy_amount': float(buy_amount),
                    'trading_version': int(tver or 0)
                }
            # self.logger.info(f"加载买入计划: {len(buy_plans)}个")
            return buy_plans
        except Exception as e:
            self.logger.error(f"获取买入计划失败: {str(e)}")
            return {}
    
    def get_active_sell_plans(self, strategy_id: int = 1) -> Dict[str, Dict]:
        """获取激活的卖出计划（仅当日最新记录）"""
        sql = """
        SELECT t.stock_code, t.stock_name, t.target_price, t.sell_quantity, t.trading_version
        FROM trading_sell_plan t
        JOIN (
          SELECT stock_code, MAX(update_time) AS max_ut
          FROM trading_sell_plan
          WHERE strategy_id=%s AND is_active=1 AND DATE(trading_time)=CURDATE()
          GROUP BY stock_code
        ) m ON t.stock_code=m.stock_code AND t.update_time=m.max_ut
        WHERE t.strategy_id=%s AND t.is_active=1
        """
        try:
            results = self.execute_query(sql, (strategy_id, strategy_id))
            sell_plans = {}
            for row in results:
                stock_code, stock_name, target_price, sell_quantity, tver = row
                sell_plans[stock_code] = {
                    'stock_name': stock_name,
                    'target_price': float(target_price),
                    'sell_quantity': sell_quantity,
                    'trading_version': int(tver or 0)
                }
            # self.logger.info(f"加载卖出计划: {len(sell_plans)}个")
            return sell_plans
        except Exception as e:
            self.logger.error(f"获取卖出计划失败: {str(e)}")
            return {}

    # ===== Plan versioned read (optional trading_version column) =====
    def get_max_plan_version(self, strategy_id: int = 1) -> int:
        """获取买/卖计划的最大版本号（需要表中存在 trading_version 列）。若列不存在返回0。"""
        try:
            buy_sql = "SELECT COALESCE(MAX(trading_version), 0) FROM trading_buy_plan WHERE strategy_id=%s AND is_active=1"
            sell_sql = "SELECT COALESCE(MAX(trading_version), 0) FROM trading_sell_plan WHERE strategy_id=%s AND is_active=1"
            bmax = self.execute_query(buy_sql, (strategy_id,))[0][0]
            smax = self.execute_query(sell_sql, (strategy_id,))[0][0]
            return max(int(bmax or 0), int(smax or 0))
        except Exception as e:
            self.logger.warning(f"读取最大计划版本失败，可能缺少 trading_version 列: {str(e)}")
            return 0

    def get_buy_plans_since(self, strategy_id: int, version: int) -> Dict[str, Dict]:
        """获取版本号大于给定值的买入计划（需要 trading_version 列）。列缺失时返回全部激活计划。"""
        try:
            sql = """
            SELECT stock_code, stock_name, target_price, buy_amount, trading_version
            FROM trading_buy_plan WHERE strategy_id=%s AND is_active=1 AND trading_version>%s
            """
            results = self.execute_query(sql, (strategy_id, version))
            plans = {}
            for row in results:
                stock_code, stock_name, target_price, buy_amount, tver = row
                plans[stock_code] = {
                    'stock_name': stock_name,
                    'target_price': float(target_price),
                    'buy_amount': float(buy_amount),
                    'trading_version': int(tver or 0)
                }
            return plans
        except Exception:
            # 回退到全部激活计划
            return self.get_active_buy_plans(strategy_id)

    def get_sell_plans_since(self, strategy_id: int, version: int) -> Dict[str, Dict]:
        """获取版本号大于给定值的卖出计划（需要 trading_version 列）。列缺失时返回全部激活计划。"""
        try:
            sql = """
            SELECT stock_code, stock_name, target_price, sell_quantity, trading_version
            FROM trading_sell_plan WHERE strategy_id=%s AND is_active=1 AND trading_version>%s
            """
            results = self.execute_query(sql, (strategy_id, version))
            plans = {}
            for row in results:
                stock_code, stock_name, target_price, sell_quantity, tver = row
                plans[stock_code] = {
                    'stock_name': stock_name,
                    'target_price': float(target_price),
                    'sell_quantity': sell_quantity,
                    'trading_version': int(tver or 0)
                }
            return plans
        except Exception:
            return self.get_active_sell_plans(strategy_id)
    
    def insert_order(self, order_data: Dict) -> bool:
        """插入订单记录"""
        sql = """
        INSERT INTO trading_order 
        (order_id, strategy_id, stock_code, order_side, order_quantity, order_price, target_price,
         order_status, order_time, order_remark)
        VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
        """
        try:
            params = (
                order_data['order_id'],
                order_data['strategy_id'],
                order_data['stock_code'],
                order_data['order_side'],
                order_data['order_quantity'],
                order_data['order_price'],
                order_data['target_price'],
                order_data['order_status'],
                order_data['order_time'],
                order_data['order_remark']
            )
            self.execute_update(sql, params)
            self.logger.info(f"订单记录已插入: {order_data['order_id']}")
            return True
        except Exception as e:
            self.logger.error(f"插入订单记录失败: {str(e)}")
            return False
    
    def update_order_status(self, order_id: str, status: str, filled_quantity: int = None, filled_time: str = None) -> bool:
        """更新订单状态"""
        try:
            # 添加调试信息
            self.logger.info(f"准备更新订单状态: order_id={order_id} (类型: {type(order_id)}), status={status}")
            
            # 确保 order_id 是字符串类型
            order_id_str = str(order_id)
            
            if filled_quantity is not None and filled_time:
                sql = """
                UPDATE trading_order 
                SET order_status = %s, filled_quantity = %s, filled_time = %s
                WHERE order_id = %s OR qmt_order_id = %s
                """
                params = (status, filled_quantity, filled_time, order_id_str, order_id_str)
            else:
                sql = """
                UPDATE trading_order 
                SET order_status = %s
                WHERE order_id = %s OR qmt_order_id = %s
                """
                params = (status, order_id_str, order_id_str)
            
            # 添加 SQL 调试信息
            self.logger.info(f"执行 SQL: {sql}")
            self.logger.info(f"参数: {params}")
            
            affected_rows = self.execute_update(sql, params)
            # if affected_rows > 0:
            self.logger.info(f"订单状态已更新: {order_id_str} -> {status}")
            return True
            # else:
            #     self.logger.warning(f"订单状态更新失败，未找到订单: {order_id_str}")
            #     return False
        except Exception as e:
            self.logger.error(f"更新订单状态失败: {str(e)}")
            return False
    
    def update_qmt_order_id(self, our_order_id: str, qmt_order_id: str) -> bool:
        """更新QMT内部订单ID"""
        try:
            sql = """
            UPDATE trading_order 
            SET qmt_order_id = %s
            WHERE order_id = %s
            """
            params = (str(qmt_order_id), our_order_id)
            
            affected_rows = self.execute_update(sql, params)
            # if affected_rows > 0:
            self.logger.info(f"QMT订单ID已更新: {our_order_id} -> {qmt_order_id}")
            return True
            # else:
            #     self.logger.warning(f"更新QMT订单ID失败，未找到订单: {our_order_id}")
            #     return False
        except Exception as e:
            self.logger.error(f"更新QMT订单ID失败: {str(e)}")
            return False
    
    def update_position(self, stock_code: str, quantity_change: int, price: float, is_buy: bool) -> bool:
        """更新持仓"""
        try:
            # 先查询当前持仓
            sql_select = "SELECT total_quantity, cost_price FROM trading_position WHERE stock_code = %s"
            results = self.execute_query(sql_select, (stock_code,))
            
            if results:
                # 更新现有持仓
                current_quantity, current_cost_price = results[0]
                
                # 确保类型转换，避免 Decimal 和 float 混合运算
                current_cost_price = float(current_cost_price) if current_cost_price is not None else 0.0
                price = float(price)
                
                if is_buy:
                    # 买入：增加持仓
                    new_quantity = current_quantity + quantity_change
                    if current_quantity > 0:
                        new_cost_price = (current_cost_price * current_quantity + price * quantity_change) / new_quantity
                    else:
                        new_cost_price = price
                else:
                    # 卖出：减少持仓
                    new_quantity = max(0, current_quantity - quantity_change)
                    new_cost_price = current_cost_price if new_quantity > 0 else 0.0
                
                if new_quantity > 0:
                    sql_update = """
                    UPDATE trading_position 
                    SET total_quantity = %s, cost_price = %s, update_time = NOW()
                    WHERE stock_code = %s
                    """
                    self.execute_update(sql_update, (new_quantity, new_cost_price, stock_code))
                else:
                    # 持仓为0，删除记录
                    sql_delete = "DELETE FROM trading_position WHERE stock_code = %s"
                    self.execute_update(sql_delete, (stock_code,))
            else:
                # 新增持仓（仅买入时）
                if is_buy and quantity_change > 0:
                    sql_insert = """
                    INSERT INTO trading_position 
                    (stock_code, total_quantity, cost_price, create_time, update_time)
                    VALUES (%s, %s, %s, NOW(), NOW())
                    """
                    self.execute_update(sql_insert, (stock_code, quantity_change, float(price)))
            
            self.logger.info(f"持仓已更新: {stock_code} {'买入' if is_buy else '卖出'} {quantity_change}股")
            return True
        except Exception as e:
            self.logger.error(f"更新持仓失败: {str(e)}")
            return False
    
    def insert_trading_log(self, log_data: Dict) -> bool:
        """插入交易日志"""
        import json
        sql = """
        INSERT INTO trading_log 
        (order_id, stock_code, log_type, log_level, message, extra_data, create_time)
        VALUES (%s, %s, %s, %s, %s, %s, %s)
        """
        try:
            # 将extra_data转换为JSON字符串
            extra_data_json = json.dumps(log_data.get('extra_data'), ensure_ascii=False) if log_data.get('extra_data') else None
            
            params = (
                log_data.get('order_id'),
                log_data.get('stock_code'),
                log_data['log_type'],
                log_data['log_level'],
                log_data['message'],
                extra_data_json,
                log_data['create_time']
            )
            self.execute_update(sql, params)
            return True
        except Exception as e:
            self.logger.error(f"插入交易日志失败: {str(e)}")
            return False
    
    def get_current_positions(self) -> Dict[str, int]:
        """获取当前持仓"""
        sql = "SELECT stock_code, total_quantity FROM trading_position WHERE total_quantity > 0"
        try:
            results = self.execute_query(sql)
            positions = {row[0]: row[1] for row in results}
            self.logger.info(f"从数据库加载持仓: {positions}")
            return positions
        except Exception as e:
            self.logger.error(f"获取当前持仓失败: {str(e)}")
            return {}

    def get_open_orders(self) -> Dict[str, Dict]:
        """获取未完成订单（pending/submitted）"""
        sql = """
        SELECT order_id, stock_code, order_side, order_quantity, order_price, order_status, order_time
        FROM trading_order
        WHERE order_status IN ('pending','submitted')
        """
        try:
            results = self.execute_query(sql)
            orders = {}
            for row in results:
                order_id, stock_code, side, qty, price, status, order_time = row
                orders[stock_code] = {
                    'order_id': order_id,
                    'order_quantity': qty,
                    'order_price': float(price) if price is not None else None,
                    'status': status,
                    'side': side,
                    'order_time': order_time.strftime('%Y-%m-%d %H:%M:%S') if order_time else None
                }
            return orders
        except Exception as e:
            self.logger.error(f"获取未完成订单失败: {str(e)}")
            return {}

    def get_todays_orders_by_statuses(self, statuses: List[str]) -> List[Dict]:
        """获取今日指定状态集合的订单列表"""
        if not statuses:
            return []
        placeholders = ','.join(['%s'] * len(statuses))
        sql = f"""
        SELECT order_id, stock_code, order_side, order_quantity, order_price, order_status, order_time
        FROM trading_order
        WHERE DATE(order_time)=CURDATE() AND order_status IN ({placeholders})
        ORDER BY order_time ASC
        """
        try:
            results = self.execute_query(sql, tuple(statuses))
            orders: List[Dict] = []
            for row in results:
                order_id, stock_code, side, qty, price, status, order_time = row
                orders.append({
                    'order_id': str(order_id),
                    'stock_code': stock_code,
                    'side': side,
                    'order_quantity': int(qty) if qty is not None else 0,
                    'order_price': float(price) if price is not None else None,
                    'order_status': status,
                    'order_time': order_time,
                })
            return orders
        except Exception as e:
            self.logger.error(f"获取今日订单失败: {str(e)}")
            return []

    # ===== 清仓请求管理 =====
    def get_pending_clearance_requests(self) -> Dict[str, Dict]:
        """获取待处理的清仓请求（status='pending'）"""
        sql = """
        SELECT id, stock_code, stock_name, status, requested_by, request_time, reason
        FROM trading_clearance_request
        WHERE status = 'pending'
        ORDER BY request_time ASC
        """
        try:
            results = self.execute_query(sql)
            clearance_requests = {}
            for row in results:
                req_id, stock_code, stock_name, status, requested_by, request_time, reason = row
                clearance_requests[stock_code] = {
                    'id': req_id,
                    'stock_name': stock_name,
                    'status': status,
                    'requested_by': requested_by,
                    'request_time': request_time.strftime('%Y-%m-%d %H:%M:%S') if request_time else None,
                    'reason': reason
                }
            return clearance_requests
        except Exception as e:
            self.logger.error(f"获取待清仓请求失败: {str(e)}")
            return {}

    def update_clearance_status(self, stock_code: str, status: str, completed_time: str = None) -> bool:
        """更新清仓请求状态"""
        try:
            if completed_time:
                sql = """
                UPDATE trading_clearance_request 
                SET status = %s, completed_time = %s
                WHERE stock_code = %s AND status = 'pending'
                """
                params = (status, completed_time, stock_code)
            else:
                sql = """
                UPDATE trading_clearance_request 
                SET status = %s
                WHERE stock_code = %s AND status = 'pending'
                """
                params = (status, stock_code)
            
            affected_rows = self.execute_update(sql, params)
            if affected_rows > 0:
                self.logger.info(f"清仓请求状态已更新: {stock_code} -> {status}")
                return True
            else:
                self.logger.warning(f"清仓请求状态更新失败，未找到待处理请求: {stock_code}")
                return False
        except Exception as e:
            self.logger.error(f"更新清仓请求状态失败: {str(e)}")
            return False

    # ===== 持仓快照同步（覆盖式） =====
    def upsert_position_snapshot(self, stock_code: str, total_quantity: int, available_quantity: int, 
                                frozen_quantity: int, cost_price: float, market_price: float, 
                                market_value: float, profit_loss: float, profit_loss_ratio: float) -> None:
        """按快照覆盖更新单条持仓（存在则更新，不存在则插入）"""
        sql = """
        INSERT INTO trading_position 
        (stock_code, total_quantity, available_quantity, frozen_quantity, cost_price, 
         market_price, market_value, profit_loss, profit_loss_ratio, create_time, update_time)
        VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, NOW(), NOW())
        ON DUPLICATE KEY UPDATE 
        total_quantity=VALUES(total_quantity), 
        available_quantity=VALUES(available_quantity),
        frozen_quantity=VALUES(frozen_quantity),
        cost_price=VALUES(cost_price), 
        market_price=VALUES(market_price),
        market_value=VALUES(market_value),
        profit_loss=VALUES(profit_loss),
        profit_loss_ratio=VALUES(profit_loss_ratio),
        update_time=NOW()
        """
        self.execute_update(sql, (stock_code, total_quantity, available_quantity, frozen_quantity, 
                                cost_price, market_price, market_value, profit_loss, profit_loss_ratio))

    def delete_positions_except(self, stock_codes: List[str]) -> None:
        """删除不在给定集合中的所有持仓记录（用于快照清理）"""
        if not stock_codes:
            # 如果为空，清空整表
            sql = "DELETE FROM trading_position"
            self.execute_update(sql)
            return
        placeholders = ','.join(['%s'] * len(stock_codes))
        sql = f"DELETE FROM trading_position WHERE stock_code NOT IN ({placeholders})"
        self.execute_update(sql, tuple(stock_codes))

    def update_account_funds(self, account_id: str, account_type: str, total_asset: float, 
                           available_cash: float, frozen_cash: float, market_value: float, 
                           profit_loss: float, profit_loss_ratio: float) -> bool:
        """更新账户资金信息"""
        try:
            sql = """
            INSERT INTO trading_account_funds 
            (account_id, account_type, total_asset, available_cash, frozen_cash, 
             market_value, profit_loss, profit_loss_ratio, update_time)
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, NOW())
            ON DUPLICATE KEY UPDATE
            account_type = VALUES(account_type),
            total_asset = VALUES(total_asset),
            available_cash = VALUES(available_cash),
            frozen_cash = VALUES(frozen_cash),
            market_value = VALUES(market_value),
            profit_loss = VALUES(profit_loss),
            profit_loss_ratio = VALUES(profit_loss_ratio),
            update_time = NOW()
            """
            params = (account_id, account_type, total_asset, available_cash, 
                     frozen_cash, market_value, profit_loss, profit_loss_ratio)
            
            affected_rows = self.execute_update(sql, params)
            if affected_rows > 0:
                self.logger.info(f"账户资金信息更新成功: {account_id}")
                return True
            else:
                self.logger.warning(f"账户资金信息更新失败: {account_id}")
                return False
        except Exception as e:
            self.logger.error(f"更新账户资金信息失败: {str(e)}")
            return False

    def get_account_funds(self, account_id: str) -> Optional[Dict]:
        """获取账户资金信息"""
        try:
            sql = "SELECT * FROM trading_account_funds WHERE account_id = %s ORDER BY update_time DESC LIMIT 1"
            result = self.execute_query(sql, (account_id,))
            
            if result:
                row = result[0]
                return {
                    'id': row[0],
                    'account_id': row[1],
                    'account_type': row[2],
                    'total_asset': float(row[3]),
                    'available_cash': float(row[4]),
                    'frozen_cash': float(row[5]),
                    'market_value': float(row[6]),
                    'profit_loss': float(row[7]),
                    'profit_loss_ratio': float(row[8]),
                    'update_time': row[9],
                    'create_time': row[10]
                }
            return None
        except Exception as e:
            self.logger.error(f"获取账户资金信息失败: {str(e)}")
            return None

    def get_account_funds_history(self, account_id: str, days: int = 7) -> List[Dict]:
        """获取账户资金历史记录"""
        try:
            sql = """
            SELECT * FROM trading_account_funds 
            WHERE account_id = %s 
            AND update_time >= DATE_SUB(NOW(), INTERVAL %s DAY)
            ORDER BY update_time DESC
            """
            result = self.execute_query(sql, (account_id, days))
            
            funds_history = []
            for row in result:
                funds_history.append({
                    'id': row[0],
                    'account_id': row[1],
                    'account_type': row[2],
                    'total_asset': float(row[3]),
                    'available_cash': float(row[4]),
                    'frozen_cash': float(row[5]),
                    'market_value': float(row[6]),
                    'profit_loss': float(row[7]),
                    'profit_loss_ratio': float(row[8]),
                    'update_time': row[9],
                    'create_time': row[10]
                })
            return funds_history
        except Exception as e:
            self.logger.error(f"获取账户资金历史记录失败: {str(e)}")
            return []

    def close(self):
        """关闭数据库连接池（注意：这里不需要关闭，因为池是全局的）"""
        # DBUtils.PooledDB 的池是全局的，不需要在这里关闭
        # 应该在应用退出时调用 close_pool() 函数
        pass