"""
标签关联分析API接口
提供Web端调用入口
"""

import logging
import sys
import os
import json
import threading
import time
from typing import Dict, Any, List, Optional
from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker
import redis

# 导入配置
try:
    from valuation_analysis.config import DB_CONFIG_TAG_ANALYSIS, MONGO_CONFIG222, REDIS_CONFIG
except ImportError:
    try:
        from src.valuation_analysis.config import DB_CONFIG_TAG_ANALYSIS, MONGO_CONFIG222, REDIS_CONFIG
    except ImportError:
        # 添加项目路径
        ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
        sys.path.append(ROOT_DIR)
        from src.valuation_analysis.config import DB_CONFIG_TAG_ANALYSIS, MONGO_CONFIG222, REDIS_CONFIG

# 导入服务类
try:
    from .tag_relation_service import TagRelationService
except ImportError:
    sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
    from stock_tag_analysis.tag_relation_service import TagRelationService

# 设置日志记录
logger = logging.getLogger(__name__)


class TagRelationAPI:
    """标签关联分析API类"""
    
    def __init__(self, model_type: str = "ds3_2", enable_web_search: bool = True):
        """初始化API
        
        Args:
            model_type: 大模型类型，默认为 ds3_2
            enable_web_search: 是否启用联网搜索，默认True
        """
        # 初始化服务
        self.service = TagRelationService(
            model_type=model_type,
            enable_web_search=enable_web_search
        )
        
        # 初始化MySQL连接
        self.mysql_engine = None
        self.connect_mysql()
        
        # 初始化Redis连接（用于任务队列）
        self.redis_client = None
        self.connect_redis()
        
        # 全局队列key
        self.global_queue_key = "tag_analysis_queue:global"
        
        # 线程控制
        self.global_processing_thread = None
        self.stop_processing = False
        self.thread_lock = threading.Lock()
        
        # 启动全局处理线程
        self._start_global_processing_thread()
        
        logger.info("TagRelationAPI 初始化完成，全局处理线程已启动")
    
    def connect_mysql(self):
        """连接MySQL数据库"""
        try:
            db_url = f"mysql+pymysql://{DB_CONFIG_TAG_ANALYSIS['user']}:{DB_CONFIG_TAG_ANALYSIS['password']}@{DB_CONFIG_TAG_ANALYSIS['host']}:{DB_CONFIG_TAG_ANALYSIS['port']}/{DB_CONFIG_TAG_ANALYSIS['database']}"
            
            self.mysql_engine = create_engine(
                db_url,
                pool_size=5,
                max_overflow=10,
                pool_recycle=3600,
                echo=False
            )
            
            # 测试连接
            with self.mysql_engine.connect() as conn:
                conn.execute(text("SELECT 1"))
            
            logger.info(f"MySQL数据库连接成功: {DB_CONFIG_TAG_ANALYSIS['host']}:{DB_CONFIG_TAG_ANALYSIS['port']}/{DB_CONFIG_TAG_ANALYSIS['database']}")
            
        except Exception as e:
            logger.error(f"MySQL数据库连接失败: {str(e)}")
            raise
    
    def connect_redis(self):
        """连接Redis数据库"""
        try:
            self.redis_client = redis.Redis(
                host=REDIS_CONFIG['host'],
                port=REDIS_CONFIG['port'],
                password=REDIS_CONFIG.get('password'),
                db=REDIS_CONFIG.get('db', 13),
                socket_timeout=REDIS_CONFIG.get('socket_timeout', 5),
                decode_responses=True
            )
            
            # 测试连接
            self.redis_client.ping()
            logger.info(f"Redis连接成功: {REDIS_CONFIG['host']}:{REDIS_CONFIG['port']}")
            
        except Exception as e:
            logger.error(f"Redis连接失败: {str(e)}")
            raise
    
    def analyze_tag_for_all_stocks(
        self,
        tag_name: str,
        model_type: str = "ds3_2",
        enable_web_search: bool = True,
        temperature: float = 0.7,
        max_tokens: int = 4096
    ) -> Dict[str, Any]:
        """分析所有股票与指定标签的关联性并保存到MongoDB
        
        Args:
            tag_name: 标签名称
            model_type: 大模型类型，默认ds3_2
            enable_web_search: 是否启用联网搜索，默认True
            temperature: 大模型温度参数，默认0.7
            max_tokens: 最大token数，默认4096
            
        Returns:
            Dict[str, Any]: 包含处理结果的字典
                - success: 是否成功
                - total_stocks: 总股票数
                - processed_stocks: 已处理股票数
                - success_count: 成功分析数
                - failed_count: 失败数
                - saved_count: 已保存数
                - results: 详细结果列表
                - error: 错误信息
        """
        try:
            logger.info(f"开始分析所有股票与标签 {tag_name} 的关联性")
            
            # 查询所有股票（排除黑名单）
            stock_list = self._get_stock_list()
            
            if not stock_list:
                logger.warning("未获取到股票列表")
                return {
                    "success": False,
                    "total_stocks": 0,
                    "processed_stocks": 0,
                    "success_count": 0,
                    "failed_count": 0,
                    "saved_count": 0,
                    "results": [],
                    "error": "未获取到股票列表"
                }
            
            logger.info(f"获取到 {len(stock_list)} 只股票，开始批量分析")
            
            # 批量分析并保存
            results = self.service.batch_analyze_and_save(
                stock_list=stock_list,
                tag_name=tag_name,
                temperature=temperature,
                max_tokens=max_tokens,
                save_to_db=True
            )
            
            # 统计结果
            success_count = sum(1 for r in results if r.get('success'))
            failed_count = sum(1 for r in results if not r.get('success'))
            saved_count = sum(1 for r in results if r.get('saved_to_db'))
            
            logger.info(f"分析完成 - 总数: {len(results)}, 成功: {success_count}, 失败: {failed_count}, 已保存: {saved_count}")
            
            return {
                "success": True,
                "total_stocks": len(stock_list),
                "processed_stocks": len(results),
                "success_count": success_count,
                "failed_count": failed_count,
                "saved_count": saved_count,
                "results": results,
                "error": None
            }
            
        except Exception as e:
            logger.error(f"分析过程中出错: {str(e)}", exc_info=True)
            return {
                "success": False,
                "total_stocks": 0,
                "processed_stocks": 0,
                "success_count": 0,
                "failed_count": 0,
                "saved_count": 0,
                "results": [],
                "error": str(e)
            }
    
    def _get_stock_list(self) -> List[Dict[str, str]]:
        """从MySQL数据库获取股票列表（排除黑名单、ST股票、BSE交易所）
        
        Returns:
            List[Dict[str, str]]: 股票列表，每个元素包含 stock_code 和 stock_name
        """
        try:
            # SQL查询：获取gp_code_all表中的股票，排除黑名单、ST股票、BSE交易所
            sql = """
            SELECT 
                g.gp_code_two AS stock_code,
                g.gp_name AS stock_name
            FROM gp_code_all g
            LEFT JOIN gp_blacklist b ON g.gp_code = b.stock_code
            WHERE b.stock_code IS NULL
            AND g.gp_code_two IS NOT NULL
            AND g.gp_name IS NOT NULL
            AND g.gp_name NOT LIKE '%ST%'
            AND (g.exchange IS NULL OR g.exchange != 'BSE')
            ORDER BY g.gp_code_two
            """
            
            with self.mysql_engine.connect() as conn:
                result = conn.execute(text(sql))
                rows = result.fetchall()
                
                stock_list = []
                for row in rows:
                    stock_list.append({
                        "stock_code": row[0],
                        "stock_name": row[1]
                    })
                
                logger.info(f"从数据库获取到 {len(stock_list)} 只股票（已排除黑名单）")
                return stock_list
                
        except Exception as e:
            logger.error(f"获取股票列表失败: {str(e)}", exc_info=True)
            return []
    
    def get_stock_list_count(self) -> int:
        """获取股票总数（排除黑名单、ST股票、BSE交易所）
        
        Returns:
            int: 股票总数
        """
        try:
            sql = """
            SELECT COUNT(*)
            FROM gp_code_all g
            LEFT JOIN gp_blacklist b ON g.gp_code = b.stock_code
            WHERE b.stock_code IS NULL
            AND g.gp_code_two IS NOT NULL
            AND g.gp_name IS NOT NULL
            AND g.gp_name NOT LIKE '%ST%'
            AND (g.exchange IS NULL OR g.exchange != 'BSE')
            """
            
            with self.mysql_engine.connect() as conn:
                result = conn.execute(text(sql))
                count = result.scalar()
                return count or 0
                
        except Exception as e:
            logger.error(f"获取股票总数失败: {str(e)}")
            return 0
    
    def _filter_valid_stocks(self, stock_codes: List[str]) -> List[str]:
        """过滤有效的股票代码（排除黑名单、ST股票、BSE交易所）
        
        Args:
            stock_codes: 股票代码列表（gp_code格式）
            
        Returns:
            List[str]: 过滤后的股票代码列表（gp_code_two格式）
        """
        try:
            if not stock_codes:
                return []
            
            # 使用IN子句，构建参数化查询
            placeholders = ','.join([f':code{i}' for i in range(len(stock_codes))])
            sql = f"""
            SELECT DISTINCT g.gp_code_two
            FROM gp_code_all g
            LEFT JOIN gp_blacklist b ON g.gp_code = b.stock_code
            WHERE g.gp_code IN ({placeholders})
            AND b.stock_code IS NULL
            AND g.gp_code_two IS NOT NULL
            AND g.gp_name IS NOT NULL
            AND g.gp_name NOT LIKE '%ST%'
            AND (g.exchange IS NULL OR g.exchange != 'BSE')
            """
            
            # 构建参数字典
            params = {f'code{i}': code for i, code in enumerate(stock_codes)}
            
            with self.mysql_engine.connect() as conn:
                result = conn.execute(text(sql), params)
                rows = result.fetchall()
                valid_stocks = [row[0] for row in rows if row[0]]
                
            logger.info(f"过滤股票: 输入{len(stock_codes)}只，有效{len(valid_stocks)}只")
            return valid_stocks
            
        except Exception as e:
            logger.error(f"过滤股票失败: {str(e)}", exc_info=True)
            return []
    
    def _query_hybk_stocks(self, tag_name: str) -> List[str]:
        """从gp_hybk表查询标签关联的股票代码
        
        Args:
            tag_name: 标签名称（行业名称）
            
        Returns:
            List[str]: 股票代码列表（gp_code格式）
        """
        try:
            sql = """
            SELECT DISTINCT gp_code
            FROM gp_hybk
            WHERE bk_name = :tag_name
            AND gp_code IS NOT NULL
            """
            
            with self.mysql_engine.connect() as conn:
                result = conn.execute(text(sql), {'tag_name': tag_name})
                rows = result.fetchall()
                stock_codes = [row[0] for row in rows if row[0]]
                
            logger.info(f"从gp_hybk查询到标签'{tag_name}'关联{len(stock_codes)}只股票")
            return stock_codes
            
        except Exception as e:
            logger.error(f"查询gp_hybk失败: {str(e)}")
            return []
    
    def _query_gnbk_stocks(self, tag_name: str) -> List[str]:
        """从gp_gnbk表查询标签关联的股票代码
        
        Args:
            tag_name: 标签名称（概念名称）
            
        Returns:
            List[str]: 股票代码列表（gp_code格式）
        """
        try:
            sql = """
            SELECT DISTINCT gp_code
            FROM gp_gnbk
            WHERE bk_name = :tag_name
            AND gp_code IS NOT NULL
            """
            
            with self.mysql_engine.connect() as conn:
                result = conn.execute(text(sql), {'tag_name': tag_name})
                rows = result.fetchall()
                stock_codes = [row[0] for row in rows if row[0]]
                
            logger.info(f"从gp_gnbk查询到标签'{tag_name}'关联{len(stock_codes)}只股票")
            return stock_codes
            
        except Exception as e:
            logger.error(f"查询gp_gnbk失败: {str(e)}")
            return []
    
    def init_tags_from_mysql(
        self,
        include_hybk: bool = True,
        include_gnbk: bool = True,
        overwrite_relations: bool = True
    ) -> Dict[str, Any]:
        """从MySQL的行业/概念表初始化标签及其与个股的关联关系到MongoDB
        
        Args:
            include_hybk: 是否初始化行业标签（gp_hybk）
            include_gnbk: 是否初始化概念标签（gp_gnbk）
            overwrite_relations: 是否覆盖已有的标签-个股关联关系
        
        Returns:
            Dict[str, Any]: 初始化统计结果
        """
        stats = {
            "success": True,
            "hybk": {
                "tag_count": 0,
                "relation_count": 0
            },
            "gnbk": {
                "tag_count": 0,
                "relation_count": 0
            },
            "errors": []
        }
        
        try:
            if include_hybk:
                try:
                    logger.info("开始从 gp_hybk 初始化行业标签及关联关系")
                    sql = """
                    SELECT bk_name, gp_code
                    FROM gp_hybk
                    WHERE bk_name IS NOT NULL
                    AND gp_code IS NOT NULL
                    """
                    with self.mysql_engine.connect() as conn:
                        result = conn.execute(text(sql))
                        rows = result.fetchall()
                    
                    # 聚合为 {tag_name: set(gp_code)}
                    tag_stocks_map: Dict[str, set] = {}
                    for bk_name, gp_code in rows:
                        if not bk_name or not gp_code:
                            continue
                        tag_stocks_map.setdefault(bk_name, set()).add(gp_code)
                    
                    for tag_name, stock_codes in tag_stocks_map.items():
                        try:
                            # 过滤有效股票（转为 gp_code_two）
                            valid_stocks = self._filter_valid_stocks(list(stock_codes))
                            if not valid_stocks:
                                logger.info(f"行业标签'{tag_name}'过滤后无有效股票，跳过")
                                continue
                            
                            tag_data = {
                                'tag_name': tag_name,
                                'tag_type': '行业标签',
                                'status': 'completed',
                                'progress': 100.0,
                                'source': 'hybk'
                            }
                            tag_code = self.service.database.save_tag(tag_data)
                            if not tag_code:
                                logger.warning(f"行业标签'{tag_name}'保存失败，跳过")
                                continue
                            
                            # 保存关联关系
                            self.service.database.save_tag_stock_relations(
                                tag_code,
                                valid_stocks,
                                replace_all=overwrite_relations
                            )
                            
                            stats["hybk"]["tag_count"] += 1
                            stats["hybk"]["relation_count"] += len(valid_stocks)
                        except Exception as e:
                            err_msg = f"初始化行业标签'{tag_name}'失败: {str(e)}"
                            logger.error(err_msg, exc_info=True)
                            stats["errors"].append(err_msg)
                
                except Exception as e:
                    err_msg = f"从 gp_hybk 初始化行业标签失败: {str(e)}"
                    logger.error(err_msg, exc_info=True)
                    stats["errors"].append(err_msg)
                    stats["success"] = False
            
            if include_gnbk:
                try:
                    logger.info("开始从 gp_gnbk 初始化概念标签及关联关系")
                    sql = """
                    SELECT bk_name, gp_code
                    FROM gp_gnbk
                    WHERE bk_name IS NOT NULL
                    AND gp_code IS NOT NULL
                    """
                    with self.mysql_engine.connect() as conn:
                        result = conn.execute(text(sql))
                        rows = result.fetchall()
                    
                    # 聚合为 {tag_name: set(gp_code)}
                    tag_stocks_map: Dict[str, set] = {}
                    for bk_name, gp_code in rows:
                        if not bk_name or not gp_code:
                            continue
                        tag_stocks_map.setdefault(bk_name, set()).add(gp_code)
                    
                    for tag_name, stock_codes in tag_stocks_map.items():
                        try:
                            # 过滤有效股票（转为 gp_code_two）
                            valid_stocks = self._filter_valid_stocks(list(stock_codes))
                            if not valid_stocks:
                                logger.info(f"概念标签'{tag_name}'过滤后无有效股票，跳过")
                                continue
                            
                            tag_data = {
                                'tag_name': tag_name,
                                'tag_type': '概念标签',
                                'status': 'completed',
                                'progress': 100.0,
                                'source': 'gnbk'
                            }
                            tag_code = self.service.database.save_tag(tag_data)
                            if not tag_code:
                                logger.warning(f"概念标签'{tag_name}'保存失败，跳过")
                                continue
                            
                            # 保存关联关系
                            self.service.database.save_tag_stock_relations(
                                tag_code,
                                valid_stocks,
                                replace_all=overwrite_relations
                            )
                            
                            stats["gnbk"]["tag_count"] += 1
                            stats["gnbk"]["relation_count"] += len(valid_stocks)
                        except Exception as e:
                            err_msg = f"初始化概念标签'{tag_name}'失败: {str(e)}"
                            logger.error(err_msg, exc_info=True)
                            stats["errors"].append(err_msg)
                
                except Exception as e:
                    err_msg = f"从 gp_gnbk 初始化概念标签失败: {str(e)}"
                    logger.error(err_msg, exc_info=True)
                    stats["errors"].append(err_msg)
                    stats["success"] = False
            
            return stats
        
        except Exception as e:
            err_msg = f"初始化标签失败: {str(e)}"
            logger.error(err_msg, exc_info=True)
            stats["success"] = False
            stats["errors"].append(err_msg)
            return stats
    
    def process_tag(
        self,
        tag_name: str,
        tag_type: Optional[str] = None,
        model_type: str = "ds3_2",
        enable_web_search: bool = True,
        temperature: float = 0.7,
        max_tokens: int = 4096
    ) -> Dict[str, Any]:
        """处理标签：匹配数据库或AI分析
        
        流程：
        1. 先在gp_hybk表匹配（行业标签）
        2. 如果匹配到，保存标签和关联关系
        3. 如果没匹配到，去gp_gnbk表匹配（概念标签）
        4. 如果匹配到，保存标签和关联关系
        5. 如果都没匹配到，调用AI分析（AI标签）
        
        Args:
            tag_name: 标签名称
            tag_type: 标签类型（如果已知，可选：行业标签/概念标签/自定义标签/AI标签）
            model_type: 大模型类型，默认ds3_2
            enable_web_search: 是否启用联网搜索，默认True
            temperature: 大模型温度参数，默认0.7
            max_tokens: 最大token数，默认4096
            
        Returns:
            Dict[str, Any]: 处理结果
                - success: 是否成功
                - tag_code: 标签代码
                - tag_type: 标签类型
                - source: 数据来源（hybk/gnbk/ai）
                - stock_count: 关联股票数量
                - message: 处理消息
                - error: 错误信息
        """
        try:
            logger.info(f"开始处理标签: {tag_name}")
            
            # 检查标签是否已存在
            existing_tag = self.service.database.get_tag_by_name(tag_name)
            if existing_tag:
                tag_code = existing_tag.get('tag_code')
                logger.info(f"标签已存在: {tag_name}, tag_code: {tag_code}")
                # 获取关联股票数量
                stock_codes = self.service.database.get_tag_stocks(tag_code)
                return {
                    "success": True,
                    "tag_code": tag_code,
                    "tag_type": existing_tag.get('tag_type'),
                    "source": existing_tag.get('source', 'unknown'),
                    "stock_count": len(stock_codes),
                    "message": "标签已存在",
                    "error": None
                }
            
            # 1. 先在gp_hybk表匹配（行业标签）
            hybk_stocks = self._query_hybk_stocks(tag_name)
            if hybk_stocks:
                logger.info(f"在gp_hybk表中找到标签'{tag_name}'，关联{len(hybk_stocks)}只股票")
                
                # 过滤有效股票
                valid_stocks = self._filter_valid_stocks(hybk_stocks)
                
                # 保存标签
                tag_data = {
                    'tag_name': tag_name,
                    'tag_type': tag_type or '行业标签',
                    'status': 'completed',
                    'progress': 100.0,
                    'source': 'hybk'
                }
                tag_code = self.service.database.save_tag(tag_data)
                
                if tag_code:
                    # 保存关联关系（全量替换）
                    self.service.database.save_tag_stock_relations(tag_code, valid_stocks, replace_all=True)
                    
                    return {
                        "success": True,
                        "tag_code": tag_code,
                        "tag_type": tag_data['tag_type'],
                        "source": "hybk",
                        "stock_count": len(valid_stocks),
                        "message": f"从行业板块表匹配成功，关联{len(valid_stocks)}只股票",
                        "error": None
                    }
            
            # 2. 在gp_gnbk表匹配（概念标签）
            gnbk_stocks = self._query_gnbk_stocks(tag_name)
            if gnbk_stocks:
                logger.info(f"在gp_gnbk表中找到标签'{tag_name}'，关联{len(gnbk_stocks)}只股票")
                
                # 过滤有效股票
                valid_stocks = self._filter_valid_stocks(gnbk_stocks)
                
                # 保存标签
                tag_data = {
                    'tag_name': tag_name,
                    'tag_type': tag_type or '概念标签',
                    'status': 'completed',
                    'progress': 100.0,
                    'source': 'gnbk'
                }
                tag_code = self.service.database.save_tag(tag_data)
                
                if tag_code:
                    # 保存关联关系（全量替换）
                    self.service.database.save_tag_stock_relations(tag_code, valid_stocks, replace_all=True)
                    
                    return {
                        "success": True,
                        "tag_code": tag_code,
                        "tag_type": tag_data['tag_type'],
                        "source": "gnbk",
                        "stock_count": len(valid_stocks),
                        "message": f"从概念板块表匹配成功，关联{len(valid_stocks)}只股票",
                        "error": None
                    }
            
            # 3. 都没匹配到，使用AI分析（异步队列处理）
            logger.info(f"在数据库表中未找到标签'{tag_name}'，开始AI分析（异步队列）")
            
            # 创建标签记录（状态为processing）
            tag_data = {
                'tag_name': tag_name,
                'tag_type': tag_type or 'AI标签',
                'status': 'processing',
                'progress': 0.0,
                'source': 'ai'
            }
            tag_code = self.service.database.save_tag(tag_data)
            
            if not tag_code:
                return {
                    "success": False,
                    "tag_code": None,
                    "tag_type": tag_data['tag_type'],
                    "source": "ai",
                    "stock_count": 0,
                    "message": "创建标签记录失败",
                    "error": "无法创建标签记录"
                }
            
            # 获取所有需要处理的股票列表
            stock_list = self._get_stock_list()
            total_stocks = len(stock_list)
            
            if not stock_list:
                self.service.database.update_tag_status(tag_code, 'failed', 0.0)
                return {
                    "success": False,
                    "tag_code": tag_code,
                    "tag_type": tag_data['tag_type'],
                    "source": "ai",
                    "stock_count": 0,
                    "message": "未获取到股票列表",
                    "error": "股票列表为空"
                }
            
            # 将任务添加到全局Redis队列
            for stock in stock_list:
                task = {
                    'tag_code': tag_code,
                    'tag_name': tag_name,
                    'stock_code': stock['stock_code'],
                    'stock_name': stock['stock_name'],
                    'model_type': model_type,
                    'enable_web_search': enable_web_search,
                    'temperature': temperature,
                    'max_tokens': max_tokens
                }
                self.redis_client.lpush(self.global_queue_key, json.dumps(task, ensure_ascii=False))
            
            # 记录总任务数（用于进度计算）
            self.redis_client.set(f"tag_analysis_total:{tag_code}", total_stocks)
            # 记录已处理数（初始为0）
            self.redis_client.set(f"tag_analysis_processed:{tag_code}", 0)
            
            return {
                "success": True,
                "tag_code": tag_code,
                "tag_type": tag_data['tag_type'],
                "source": "ai",
                "stock_count": 0,  # 初始为0，处理完成后会更新
                "message": f"AI分析任务已加入队列，共{total_stocks}只股票待处理",
                "error": None,
                "status": "processing"
            }
            
        except Exception as e:
            logger.error(f"处理标签失败: {str(e)}", exc_info=True)
            return {
                "success": False,
                "tag_code": None,
                "tag_type": None,
                "source": None,
                "stock_count": 0,
                "message": "处理标签时发生异常",
                "error": str(e)
            }
    
    def _start_global_processing_thread(self):
        """启动全局处理线程"""
        if self.global_processing_thread and self.global_processing_thread.is_alive():
            logger.warning("全局处理线程已存在")
            return
        
        self.stop_processing = False
        self.global_processing_thread = threading.Thread(
            target=self._process_global_queue,
            daemon=True
        )
        self.global_processing_thread.start()
        logger.info("全局处理线程已启动")
    
    def _process_global_queue(self):
        """处理全局Redis队列中的任务（持续运行）"""
        logger.info("全局队列处理线程开始运行")
        
        # 定期检查队列和MongoDB状态的间隔（秒）
        check_interval = 10
        last_check_time = 0
        
        while not self.stop_processing:
            try:
                current_time = time.time()
                
                # 定期检查队列是否为空，如果为空则更新MongoDB中processing状态的标签
                if current_time - last_check_time >= check_interval:
                    last_check_time = current_time
                    
                    # 检查队列是否为空
                    queue_length = self.redis_client.llen(self.global_queue_key)
                    
                    if queue_length == 0:
                        # 队列为空，查找MongoDB中所有processing状态的标签，标记为completed
                        processing_tags = list(self.service.database.tags_collection.find({'status': 'processing'}))
                        
                        if processing_tags:
                            logger.info(f"队列为空，发现 {len(processing_tags)} 个processing状态的标签，标记为完成")
                            
                            for tag in processing_tags:
                                tag_code = tag.get('tag_code')
                                tag_name = tag.get('tag_name')
                                
                                if not tag_code or not tag_name:
                                    continue
                                
                                try:
                                    # 标记为完成
                                    self.service.database.update_tag_status(tag_code, 'completed', 100.0)
                                    
                                    # 清理Redis键（如果存在）
                                    total_key = f"tag_analysis_total:{tag_code}"
                                    processed_key = f"tag_analysis_processed:{tag_code}"
                                    self.redis_client.delete(total_key)
                                    self.redis_client.delete(processed_key)
                                    
                                    logger.info(f"标签 {tag_name}({tag_code}) 队列为空，标记为完成")
                                except Exception as e:
                                    logger.error(f"更新标签 {tag_name}({tag_code}) 状态失败: {str(e)}")
                                    continue
                
                # 从队列右侧取出任务（FIFO），阻塞等待，超时1秒
                task_json = self.redis_client.brpop(self.global_queue_key, timeout=1)
                
                if not task_json:
                    # 超时，继续循环
                    continue
                
                # task_json是元组 (key, value)
                task_data = json.loads(task_json[1])
                tag_code = task_data.get('tag_code')
                tag_name = task_data.get('tag_name')
                stock_code = task_data.get('stock_code')
                stock_name = task_data.get('stock_name')
                
                if not all([tag_code, tag_name, stock_code, stock_name]):
                    logger.warning(f"任务数据不完整: {task_data}")
                    continue
                
                try:
                    # 检查是否已经处理过（避免重复处理）
                    existing_result = self.service.database.get_analysis_result(stock_code, tag_name)
                    
                    if existing_result:
                        # 已存在，跳过分析，直接使用已有结果
                        logger.info(f"股票 {stock_code} 与标签 {tag_name} 已存在分析结果，跳过处理")
                        relation_score = existing_result.get('relation_score', 0)
                        has_relation = existing_result.get('has_relation', False)
                        relation_type = existing_result.get('relation_type', '')
                    else:
                        # 执行分析
                        analysis_result = self.service.analyzer.analyze_tag_relation(
                            stock_code=stock_code,
                            stock_name=stock_name,
                            tag_name=tag_name,
                            temperature=task_data.get('temperature', 0.7),
                            max_tokens=task_data.get('max_tokens', 4096)
                        )
                        
                        # 保存分析结果到 tag_relation_analysis 集合
                        if analysis_result.get('success'):
                            self.service.database.save_analysis_result(analysis_result)
                            relation_score = analysis_result.get('relation_score', 0)
                            has_relation = analysis_result.get('has_relation', False)
                            relation_type = analysis_result.get('relation_type', '')
                        else:
                            # 分析失败，跳过关联关系更新
                            relation_score = 0
                            has_relation = False
                            relation_type = ''
                    
                    # 如果关联度评分>=50 且 关联类型为"直接关联"，立即更新关联关系
                    if relation_score >= 50 and has_relation and relation_type == "直接关联":
                        self.service.database.save_tag_stock_relations(
                            tag_code, 
                            [stock_code]
                        )
                    
                    # 更新已处理数
                    processed_key = f"tag_analysis_processed:{tag_code}"
                    processed_count = self.redis_client.incr(processed_key)
                    
                    # 获取总任务数
                    total_key = f"tag_analysis_total:{tag_code}"
                    total_stocks = int(self.redis_client.get(total_key) or 0)
                    
                    # 计算并更新进度
                    if total_stocks > 0:
                        progress = (processed_count / total_stocks) * 100
                        # 通过tag_name查询标签并更新进度
                        tag_info = self.service.database.get_tag_by_name(tag_name)
                        if tag_info:
                            tag_code_from_db = tag_info.get('tag_code')
                            if tag_code_from_db == tag_code:
                                self.service.database.update_tag_status(tag_code, 'processing', progress)
                    
                    # 每处理10只股票或达到总数时，检查队列中是否还有相同标签的任务
                    if processed_count % 10 == 0 or processed_count >= total_stocks:
                        self._check_and_update_tag_status(tag_code, tag_name)
                    
                except Exception as e:
                    logger.error(f"处理任务失败: {str(e)}", exc_info=True)
                    # 即使失败也要更新已处理数，避免卡住
                    processed_key = f"tag_analysis_processed:{tag_code}"
                    self.redis_client.incr(processed_key)
                    continue
            
            except Exception as e:
                logger.error(f"全局队列处理异常: {str(e)}", exc_info=True)
                time.sleep(1)  # 出错后等待1秒再继续
        
        logger.info("全局队列处理线程已停止")
    
    def _check_and_update_tag_status(self, tag_code: str, tag_name: str):
        """检查队列中是否还有相同标签的任务，如果没有则标记完成
        
        Args:
            tag_code: 标签代码
            tag_name: 标签名称
        """
        try:
            total_key = f"tag_analysis_total:{tag_code}"
            processed_key = f"tag_analysis_processed:{tag_code}"
            
            total_stocks = int(self.redis_client.get(total_key) or 0)
            processed_count = int(self.redis_client.get(processed_key) or 0)
            
            # 如果已处理数达到总数，检查队列中是否还有该标签的任务
            if processed_count >= total_stocks:
                # 检查队列中是否还有该标签的任务
                queue_length = self.redis_client.llen(self.global_queue_key)
                
                if queue_length == 0:
                    # 队列为空，标记完成
                    self.service.database.update_tag_status(tag_code, 'completed', 100.0)
                    # 清理Redis键
                    self.redis_client.delete(total_key)
                    self.redis_client.delete(processed_key)
                    logger.info(f"标签 {tag_name}({tag_code}) 处理完成，队列已空")
                else:
                    # 检查队列中是否还有该标签的任务
                    # 使用更准确的方式：遍历整个队列（由于队列可能很大，我们限制检查范围）
                    has_same_tag = False
                    # 检查队列中的所有任务（最多检查1000个，避免性能问题）
                    check_count = min(queue_length, 1000)
                    for i in range(check_count):
                        task_json = self.redis_client.lindex(self.global_queue_key, i)
                        if task_json:
                            try:
                                task_data = json.loads(task_json)
                                if task_data.get('tag_code') == tag_code:
                                    has_same_tag = True
                                    break
                            except:
                                continue
                    
                    if not has_same_tag:
                        # 队列中没有该标签的任务了，标记完成
                        self.service.database.update_tag_status(tag_code, 'completed', 100.0)
                        # 清理Redis键
                        self.redis_client.delete(total_key)
                        self.redis_client.delete(processed_key)
                        logger.info(f"标签 {tag_name}({tag_code}) 处理完成，队列中无该标签任务")
        except Exception as e:
            logger.error(f"检查标签状态失败: {str(e)}")
    
    def get_tag_progress(self, tag_code: str = None, tag_name: str = None) -> Dict[str, Any]:
        """获取标签处理进度
        
        Args:
            tag_code: 标签代码（优先使用）
            tag_name: 标签名称（如果tag_code为空则使用）
            
        Returns:
            Dict[str, Any]: 进度信息
        """
        try:
            # 根据tag_code或tag_name查询标签
            if tag_code:
                tag = self.service.database.tags_collection.find_one({'tag_code': tag_code})
            elif tag_name:
                tag = self.service.database.get_tag_by_name(tag_name)
            else:
                return {"error": "必须提供tag_code或tag_name"}
            
            if not tag:
                return {"error": "标签不存在"}
            
            tag_code = tag.get('tag_code')
            total_key = f"tag_analysis_total:{tag_code}"
            processed_key = f"tag_analysis_processed:{tag_code}"
            
            total_stocks = int(self.redis_client.get(total_key) or 0)
            processed_count = int(self.redis_client.get(processed_key) or 0)
            
            # 检查队列中该标签的剩余任务数（估算）
            queue_length = self.redis_client.llen(self.global_queue_key)
            remaining = max(0, total_stocks - processed_count) if total_stocks > 0 else 0
            
            progress = tag.get('progress', 0.0)
            status = tag.get('status', 'unknown')
            
            return {
                "tag_code": tag_code,
                "tag_name": tag.get('tag_name'),
                "status": status,
                "progress": progress,
                "total_stocks": total_stocks,
                "processed": processed_count,
                "remaining": remaining,
                "queue_length": queue_length  # 全局队列长度
            }
        except Exception as e:
            logger.error(f"获取标签进度失败: {str(e)}")
            return {"error": str(e)}
    
    def delete_tag_by_name(
        self, 
        tag_name: str, 
        delete_analysis: bool = False
    ) -> Dict[str, Any]:
        """根据标签名称删除标签及其相关数据
        
        Args:
            tag_name: 标签名称
            delete_analysis: 是否删除分析结果，默认False（只删除标签和关联关系）
            
        Returns:
            Dict[str, Any]: 删除结果
                - success: 是否成功
                - tag_code: 标签代码
                - deleted_tag: 是否删除了标签
                - deleted_relations: 删除的关联关系数量
                - deleted_analyses: 删除的分析结果数量（如果delete_analysis=True）
                - deleted_redis_keys: 删除的Redis键数量
                - message: 处理消息
                - error: 错误信息
        """
        try:
            logger.info(f"开始删除标签: {tag_name}, delete_analysis={delete_analysis}")
            
            # 先查找标签
            tag = self.service.database.get_tag_by_name(tag_name)
            if not tag:
                logger.warning(f"标签不存在: {tag_name}")
                return {
                    "success": False,
                    "tag_code": None,
                    "deleted_tag": False,
                    "deleted_relations": 0,
                    "deleted_analyses": 0,
                    "deleted_redis_keys": 0,
                    "message": f"标签不存在: {tag_name}",
                    "error": "标签不存在"
                }
            
            tag_code = tag.get('tag_code')
            
            # 1. 删除MongoDB中的标签和相关数据
            delete_result = self.service.database.delete_tag_by_name(
                tag_name=tag_name,
                delete_analysis=delete_analysis
            )
            
            if not delete_result.get('success'):
                logger.error(f"删除标签失败: {delete_result.get('error')}")
                return {
                    "success": False,
                    "tag_code": tag_code,
                    "deleted_tag": False,
                    "deleted_relations": 0,
                    "deleted_analyses": 0,
                    "deleted_redis_keys": 0,
                    "message": f"删除标签失败: {delete_result.get('error')}",
                    "error": delete_result.get('error')
                }
            
            # 2. 删除Redis中的相关键
            deleted_redis_keys = 0
            try:
                total_key = f"tag_analysis_total:{tag_code}"
                processed_key = f"tag_analysis_processed:{tag_code}"
                
                # 删除进度相关键
                if self.redis_client.exists(total_key):
                    self.redis_client.delete(total_key)
                    deleted_redis_keys += 1
                
                if self.redis_client.exists(processed_key):
                    self.redis_client.delete(processed_key)
                    deleted_redis_keys += 1
                
                # 从队列中删除该标签的任务（可选：如果队列中有该标签的任务）
                # 注意：这里只标记删除，实际任务可能在处理中，这里不做强制删除
                logger.info(f"删除Redis键: tag_code={tag_code}, 删除数量={deleted_redis_keys}")
                
            except Exception as e:
                logger.warning(f"删除Redis键失败: {str(e)}")
                # Redis删除失败不影响整体结果
            
            # 统计删除结果
            deleted_tag = delete_result.get('deleted_tag', False)
            deleted_relations = delete_result.get('deleted_relations', 0)
            deleted_analyses = delete_result.get('deleted_analyses', 0)
            
            message = f"删除成功: 标签={deleted_tag}, 关联关系={deleted_relations}条"
            if delete_analysis:
                message += f", 分析结果={deleted_analyses}条"
            message += f", Redis键={deleted_redis_keys}个"
            
            logger.info(f"标签删除完成: {tag_name}, {message}")
            
            return {
                "success": True,
                "tag_code": tag_code,
                "deleted_tag": deleted_tag,
                "deleted_relations": deleted_relations,
                "deleted_analyses": deleted_analyses,
                "deleted_redis_keys": deleted_redis_keys,
                "message": message,
                "error": None
            }
            
        except Exception as e:
            logger.error(f"删除标签失败: {str(e)}", exc_info=True)
            return {
                "success": False,
                "tag_code": None,
                "deleted_tag": False,
                "deleted_relations": 0,
                "deleted_analyses": 0,
                "deleted_redis_keys": 0,
                "message": f"删除标签时发生异常: {str(e)}",
                "error": str(e)
            }
    
    def clear_all_tags_and_relations(self) -> Dict[str, Any]:
        """清空 MongoDB 中行业/概念标签及其中间关系（不操作 Redis 队列）"""
        try:
            return self.service.database.clear_all_tags_and_relations()
        except Exception as e:
            logger.error(f"清空标签及关系失败: {str(e)}", exc_info=True)
            return {
                "success": False,
                "error": str(e)
            }

    def close(self):
        """关闭所有连接"""
        try:
            # 停止全局处理线程
            self.stop_processing = True
            if self.global_processing_thread and self.global_processing_thread.is_alive():
                logger.info("等待全局处理线程结束...")
                self.global_processing_thread.join(timeout=5)
            
            if self.mysql_engine:
                self.mysql_engine.dispose()
                logger.info("MySQL连接已关闭")
            
            if self.redis_client:
                self.redis_client.close()
                logger.info("Redis连接已关闭")
            
            self.service.close()
        except Exception as e:
            logger.error(f"关闭连接失败: {str(e)}")


if __name__ == "__main__":
    # 设置日志
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    )
    
    # 测试示例
    api = TagRelationAPI()
    
    # 测试：分析所有股票与"商业航天"标签的关联性
    result = api.analyze_tag_for_all_stocks(tag_name="商业航天")
    
    print("\n" + "="*50)
    print("分析结果统计：")
    print("="*50)
    print(f"成功: {result.get('success')}")
    print(f"总股票数: {result.get('total_stocks')}")
    print(f"已处理: {result.get('processed_stocks')}")
    print(f"成功分析: {result.get('success_count')}")
    print(f"失败: {result.get('failed_count')}")
    print(f"已保存: {result.get('saved_count')}")
    
    # 关闭连接
    api.close()

