"""
持仓分析模块

提供持仓数据获取和行业分类统计功能，包括：
1. 从外部API获取持仓数据
2. 根据股票代码获取行业分类
3. 计算各行业持仓金额和占比
"""

import requests
import logging
from typing import Dict, List, Optional
from sqlalchemy import create_engine, text

from .config import DB_URL, LOG_FILE

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler(LOG_FILE),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger("portfolio_analyzer")


class PortfolioAnalyzer:
    """持仓分析器类"""

    def __init__(self, db_url: str = DB_URL):
        """
        初始化持仓分析器
        
        Args:
            db_url: 数据库连接URL
        """
        self.engine = create_engine(
            db_url,
            pool_size=5,
            max_overflow=10,
            pool_recycle=3600
        )
        self.api_url = ("https://to.bmbs.tech/aim/app/v1/derivativeTrading/getTradingRecordList?"
                        "projectId=182AE38B8C254BC88C715D86C643A6DD,C9B533175D294648A2372CB2966BCC96&dataScope=all")
        logger.info("持仓分析器初始化完成")
    
    def get_trading_records(self) -> Optional[Dict]:
        """
        从外部API获取交易记录数据
        
        Returns:
            交易记录数据字典，如果请求失败返回None
        """
        try:
            headers = {
                'authUserIdYh': '4028816c6759b6cb01675aacc98a00f6'
            }
            
            response = requests.get(self.api_url, headers=headers, timeout=10)
            response.raise_for_status()
            
            data = response.json()
            if data.get("success") and data.get("code") == 200:
                logger.info("成功获取交易记录数据")
                return data.get("data", {})
            else:
                logger.error(f"API返回错误: {data.get('message', '未知错误')}")
                return None
                
        except requests.exceptions.RequestException as e:
            logger.error(f"请求交易记录API失败: {e}")
            return None
        except Exception as e:
            logger.error(f"处理交易记录数据失败: {e}")
            return None
    
    def get_stock_industry(self, stock_code: str) -> List[str]:
        """
        获取指定股票所属的行业列表
        
        Args:
            stock_code: 股票代码（格式如：603290.SH）
            
        Returns:
            行业名称列表
        """
        try:
            # 转换股票代码格式
            formatted_code = self._convert_stock_code_format(stock_code)
            
            query = text("""
                SELECT DISTINCT bk_name 
                FROM gp_hybk 
                WHERE gp_code = :stock_code
            """)
            
            with self.engine.connect() as conn:
                result = conn.execute(query, {"stock_code": formatted_code}).fetchall()
                
            if result:
                return [row[0] for row in result]
            else:
                logger.warning(f"未找到股票 {stock_code} 的行业数据")
                return []
                
        except Exception as e:
            logger.error(f"获取股票行业失败: {e}")
            return []
    
    def _convert_stock_code_format(self, stock_code: str) -> str:
        """
        转换股票代码格式
        
        Args:
            stock_code: 原始股票代码，格式如 "603290.SH"
            
        Returns:
            转换后的股票代码，格式如 "SH603290"
        """
        try:
            code, market = stock_code.split('.')
            return f"{market}{code}"
        except Exception as e:
            logger.error(f"转换股票代码格式失败: {str(e)}")
            return stock_code
    
    def calculate_margin_amount(self, notional_principal: float, margin_rate: float) -> float:
        """
        计算保证金金额
        
        Args:
            notional_principal: 名义本金
            margin_rate: 保证金率（百分比）
            
        Returns:
            保证金金额
        """
        return notional_principal * (margin_rate / 100)
    
    def analyze_portfolio_allocation(self) -> Dict:
        """
        分析持仓行业分配
        
        Returns:
            包含行业持仓占比的字典
        """
        try:
            # 1. 获取交易记录数据
            trading_data = self.get_trading_records()
            if not trading_data:
                return {"success": False, "message": "无法获取交易记录数据"}
            
            data_list = trading_data.get("dataList", [])
            if not data_list:
                return {"success": False, "message": "交易记录数据为空"}
            
            # 2. 处理持仓数据
            industry_amounts = {}  # 行业金额统计
            total_amount = 0.0
            
            for project in data_list:
                project_name = project.get("projectName", "")
                stock_code = project.get("stockCode", "")
                trading_records = project.get("tradingRecoderList", [])
                
                # 只处理未清仓的记录
                for record in trading_records:
                    if record.get("projectStatus") == "published":
                        notional_principal = float(record.get("notionalPrincipal", 0))
                        margin_rate = float(record.get("marginRate", 0))
                        
                        # 计算保证金金额
                        margin_amount = self.calculate_margin_amount(notional_principal, margin_rate)
                        total_amount += margin_amount
                        
                        # 获取股票所属行业
                        industries = self.get_stock_industry(stock_code)
                        
                        if industries:
                            # 如果股票属于多个行业，按行业数量平均分配
                            amount_per_industry = margin_amount / len(industries)
                            for industry in industries:
                                if industry in industry_amounts:
                                    industry_amounts[industry] += amount_per_industry
                                else:
                                    industry_amounts[industry] = amount_per_industry
                        else:
                            # 如果无法获取行业信息，归类为"其他"
                            other_industry = "其他"
                            if other_industry in industry_amounts:
                                industry_amounts[other_industry] += margin_amount
                            else:
                                industry_amounts[other_industry] = margin_amount
            
            # 3. 生成返回数据
            if not industry_amounts:
                return {"success": False, "message": "未找到有效的持仓数据"}
            
            # 按金额排序
            sorted_industries = sorted(industry_amounts.items(), key=lambda x: x[1], reverse=True)
            
            # 定义颜色映射
            colors = [
                "#5470c6", "#91cc75", "#fac858", "#ee6666", "#73c0de",
                "#3ba272", "#fc8452", "#9a60b4", "#ea7ccc", "#ff9f7f"
            ]
            
            industries_data = []
            for i, (industry, amount) in enumerate(sorted_industries):
                color = colors[i % len(colors)]
                industries_data.append({
                    "industry": industry,
                    "amount": round(amount, 2),
                    "color": color
                })
            
            result = {
                "success": True,
                "data": {
                    "total_amount": round(total_amount, 2),
                    "industries": industries_data
                }
            }
            
            logger.info(f"成功分析持仓行业分配，总金额: {total_amount:.2f}元，共{len(industries_data)}个行业")
            return result
            
        except Exception as e:
            logger.error(f"分析持仓行业分配失败: {e}")
            return {"success": False, "message": f"分析持仓行业分配失败: {str(e)}"}
    
    def get_portfolio_summary(self) -> Dict:
        """
        获取持仓摘要信息
        
        Returns:
            持仓摘要信息字典
        """
        try:
            # 1. 获取交易记录数据
            trading_data = self.get_trading_records()
            if not trading_data:
                return {"success": False, "message": "无法获取交易记录数据"}
            
            data_list = trading_data.get("dataList", [])
            if not data_list:
                return {"success": False, "message": "交易记录数据为空"}
            
            # 2. 统计信息
            total_projects = len(data_list)
            active_projects = 0
            total_margin_amount = 0.0
            project_details = []
            
            for project in data_list:
                project_name = project.get("projectName", "")
                stock_code = project.get("stockCode", "")
                trading_records = project.get("tradingRecoderList", [])
                
                project_margin = 0.0
                has_active_position = False
                
                for record in trading_records:
                    if record.get("projectStatus") == "published":
                        has_active_position = True
                        notional_principal = float(record.get("notionalPrincipal", 0))
                        margin_rate = float(record.get("marginRate", 0))
                        margin_amount = self.calculate_margin_amount(notional_principal, margin_rate)
                        project_margin += margin_amount
                
                if has_active_position:
                    active_projects += 1
                    total_margin_amount += project_margin
                    
                    # 获取行业信息
                    industries = self.get_stock_industry(stock_code)
                    industry_names = ", ".join(industries) if industries else "未知"
                    
                    project_details.append({
                        "project_name": project_name,
                        "stock_code": stock_code,
                        "industry": industry_names,
                        "margin_amount": round(project_margin, 2)
                    })
            
            # 3. 生成摘要
            summary = {
                "success": True,
                "data": {
                    "total_projects": total_projects,
                    "active_projects": active_projects,
                    "total_margin_amount": round(total_margin_amount, 2),
                    "project_details": project_details
                }
            }
            
            logger.info(f"成功获取持仓摘要，总项目数: {total_projects}，活跃项目数: {active_projects}")
            return summary
            
        except Exception as e:
            logger.error(f"获取持仓摘要失败: {e}")
            return {"success": False, "message": f"获取持仓摘要失败: {str(e)}"} 

    def get_industry_holdings_detail(self, industry_name: str) -> Dict:
        """
        获取指定行业的详细持仓信息
        
        Args:
            industry_name: 行业名称
            
        Returns:
            包含行业详细持仓信息的字典
        """
        try:
            # 1. 获取交易记录数据
            trading_data = self.get_trading_records()
            if not trading_data:
                return {"success": False, "message": "无法获取交易记录数据"}
            
            data_list = trading_data.get("dataList", [])
            if not data_list:
                return {"success": False, "message": "交易记录数据为空"}
            
            # 2. 筛选该行业的持仓记录
            industry_holdings = []
            
            for project in data_list:
                project_name = project.get("projectName", "")
                stock_code = project.get("stockCode", "")
                trading_records = project.get("tradingRecoderList", [])
                
                # 获取股票所属行业
                industries = self.get_stock_industry(stock_code)
                
                # 检查是否属于指定行业
                if industry_name in industries:
                    for record in trading_records:
                        if record.get("projectStatus") == "published":
                            notional_principal = float(record.get("notionalPrincipal", 0))
                            margin_rate = float(record.get("marginRate", 0))
                            create_time = record.get("createTime", "")
                            
                            # 计算保证金金额
                            margin_amount = self.calculate_margin_amount(notional_principal, margin_rate)
                            
                            industry_holdings.append({
                                "project_name": project_name,
                                "stock_code": stock_code,
                                "notional_principal": notional_principal,
                                "margin_rate": margin_rate,
                                "margin_amount": margin_amount,
                                "create_time": create_time
                            })
            
            # 3. 按保证金金额排序
            industry_holdings.sort(key=lambda x: x["margin_amount"], reverse=True)
            
            # 4. 生成返回数据
            result = {
                "success": True,
                "data": {
                    "industry_name": industry_name,
                    "total_count": len(industry_holdings),
                    "total_margin_amount": sum(item["margin_amount"] for item in industry_holdings),
                    "holdings": industry_holdings
                }
            }
            
            logger.info(f"成功获取行业 {industry_name} 的详细持仓信息，共 {len(industry_holdings)} 条记录")
            return result
            
        except Exception as e:
            logger.error(f"获取行业详细持仓信息失败: {e}")
            return {"success": False, "message": f"获取行业详细持仓信息失败: {str(e)}"} 