"""
TradingAgents免费基本面分析师

该模块实现使用免费数据源的基本面分析师智能体，替代原有的付费FinnHub基本面分析师。
使用SEC Edgar和Yahoo Finance等免费数据源进行深度基本面分析。

@author TradingAgents团队
@version MVP-1.0
@since 2024-12
"""

import asyncio
import logging
from datetime import datetime, timedelta
from typing import Dict, Any, List, Optional, Tuple
from dataclasses import dataclass

from langchain.schema import BaseMessage, HumanMessage, SystemMessage
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field

from tradingagents.dataflows.free_alternatives import (
    SECEdgarClient, 
    EnhancedYahooFinanceClient,
    DataSourceConfig,
    create_free_data_sources
)
from tradingagents.config.free_config import get_config

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


@dataclass
class FundamentalMetrics:
    """
    基本面指标数据类
    
    @description 标准化的基本面指标结构
    """
    # 估值指标
    pe_ratio: Optional[float] = None
    pb_ratio: Optional[float] = None
    ps_ratio: Optional[float] = None
    ev_ebitda: Optional[float] = None
    
    # 盈利能力指标
    roe: Optional[float] = None  # 净资产收益率
    roa: Optional[float] = None  # 总资产收益率
    net_margin: Optional[float] = None  # 净利润率
    gross_margin: Optional[float] = None  # 毛利率
    
    # 财务健康指标
    debt_to_equity: Optional[float] = None
    current_ratio: Optional[float] = None
    quick_ratio: Optional[float] = None
    interest_coverage: Optional[float] = None
    
    # 增长指标
    revenue_growth: Optional[float] = None
    earnings_growth: Optional[float] = None
    book_value_growth: Optional[float] = None
    
    # 分红指标
    dividend_yield: Optional[float] = None
    payout_ratio: Optional[float] = None
    
    # 数据质量指标
    data_completeness: float = 0.0
    last_updated: Optional[str] = None
    data_sources: List[str] = None
    
    def __post_init__(self):
        if self.data_sources is None:
            self.data_sources = []


class FundamentalAnalysisResult(BaseModel):
    """
    基本面分析结果模型
    
    @description Pydantic模型，用于结构化LLM输出
    """
    ticker: str = Field(description="股票代码")
    analysis_date: str = Field(description="分析日期")
    
    # 综合评分 (0-100)
    fundamental_score: int = Field(description="基本面综合评分", ge=0, le=100)
    
    # 分类评分
    valuation_score: int = Field(description="估值评分", ge=0, le=100)
    profitability_score: int = Field(description="盈利能力评分", ge=0, le=100)
    financial_health_score: int = Field(description="财务健康评分", ge=0, le=100)
    growth_score: int = Field(description="增长潜力评分", ge=0, le=100)
    
    # 投资建议
    recommendation: str = Field(description="投资建议", regex="^(强烈买入|买入|持有|卖出|强烈卖出)$")
    confidence_level: float = Field(description="置信度", ge=0.0, le=1.0)
    
    # 关键发现
    key_strengths: List[str] = Field(description="主要优势")
    key_weaknesses: List[str] = Field(description="主要劣势")
    risk_factors: List[str] = Field(description="风险因素")
    
    # 详细分析
    valuation_analysis: str = Field(description="估值分析")
    profitability_analysis: str = Field(description="盈利能力分析")
    financial_health_analysis: str = Field(description="财务健康分析")
    growth_analysis: str = Field(description="增长分析")
    
    # 目标价格
    target_price: Optional[float] = Field(description="目标价格")
    price_range_low: Optional[float] = Field(description="价格区间下限")
    price_range_high: Optional[float] = Field(description="价格区间上限")
    
    # 数据质量
    data_quality_score: int = Field(description="数据质量评分", ge=0, le=100)
    limitations: List[str] = Field(description="分析局限性")


class FreeFundamentalsAnalyst:
    """
    免费基本面分析师
    
    @description 使用免费数据源进行基本面分析的智能体
    @version MVP-1.0
    """
    
    def __init__(self, config: Optional[Dict[str, Any]] = None):
        """
        初始化免费基本面分析师
        
        @param {Optional[Dict[str, Any]]} config - 配置参数
        """
        self.config = get_config()
        self.custom_config = config or {}
        
        # 初始化LLM
        self.llm = ChatOpenAI(
            model=self.config.openai_model,
            temperature=self.config.openai_temperature,
            max_tokens=self.config.openai_max_tokens,
            openai_api_key=self.config.openai_api_key
        )
        
        # 初始化数据源
        data_source_config = DataSourceConfig(
            alpha_vantage_api_key=self.config.data_sources.alpha_vantage_api_key,
            max_daily_calls=self.config.data_sources.alpha_vantage_max_calls_per_day,
            cache_ttl_hours=self.config.data_sources.cache_ttl_hours,
            user_agent=self.config.data_sources.sec_edgar_user_agent
        )
        
        self.data_sources = create_free_data_sources(data_source_config)
        
        # 初始化输出解析器
        self.output_parser = PydanticOutputParser(pydantic_object=FundamentalAnalysisResult)
        
        # 创建分析提示模板
        self._create_analysis_prompt()
        
        logger.info("免费基本面分析师初始化完成")
    
    def _create_analysis_prompt(self):
        """创建分析提示模板"""
        system_prompt = """你是一位专业的基本面分析师，专门分析股票的内在价值和投资潜力。

你的任务是基于提供的财务数据和基本面指标，进行深度的基本面分析，并给出投资建议。

分析框架：
1. 估值分析：PE、PB、PS等估值指标是否合理
2. 盈利能力：ROE、ROA、利润率等盈利指标
3. 财务健康：债务水平、流动性、偿债能力
4. 增长潜力：收入增长、利润增长、市场前景

评分标准：
- 90-100分：优秀，强烈推荐
- 80-89分：良好，推荐买入
- 70-79分：一般，可以持有
- 60-69分：较差，建议观望
- 0-59分：很差，建议卖出

请确保分析客观、专业，基于数据而非情绪。同时要考虑数据的局限性和分析的不确定性。

{format_instructions}"""
        
        human_prompt = """请分析以下股票的基本面：

股票代码：{ticker}
当前价格：${current_price}
分析日期：{analysis_date}

=== SEC Edgar数据 ===
{sec_data}

=== Yahoo Finance增强数据 ===
{yahoo_data}

=== 计算的基本面指标 ===
{fundamental_metrics}

=== 行业对比数据 ===
{industry_comparison}

请进行全面的基本面分析，包括估值、盈利能力、财务健康和增长潜力四个维度。"""
        
        self.analysis_prompt = ChatPromptTemplate.from_messages([
            ("system", system_prompt),
            ("human", human_prompt)
        ])
    
    async def analyze_fundamentals(
        self, 
        ticker: str, 
        include_industry_comparison: bool = True
    ) -> FundamentalAnalysisResult:
        """
        执行基本面分析
        
        @param {str} ticker - 股票代码
        @param {bool} include_industry_comparison - 是否包含行业对比
        @returns {FundamentalAnalysisResult} 分析结果
        """
        try:
            logger.info(f"开始基本面分析: {ticker}")
            
            # 并行获取数据
            sec_data, yahoo_data = await asyncio.gather(
                self._get_sec_data(ticker),
                self._get_yahoo_data(ticker),
                return_exceptions=True
            )
            
            # 处理异常
            if isinstance(sec_data, Exception):
                logger.warning(f"SEC数据获取失败: {sec_data}")
                sec_data = {}
            
            if isinstance(yahoo_data, Exception):
                logger.warning(f"Yahoo数据获取失败: {yahoo_data}")
                yahoo_data = {}
            
            # 计算基本面指标
            fundamental_metrics = self._calculate_fundamental_metrics(sec_data, yahoo_data)
            
            # 获取行业对比数据
            industry_comparison = {}
            if include_industry_comparison:
                try:
                    industry_comparison = await self._get_industry_comparison(ticker, yahoo_data)
                except Exception as e:
                    logger.warning(f"行业对比数据获取失败: {e}")
            
            # 准备分析数据
            analysis_data = {
                "ticker": ticker.upper(),
                "current_price": yahoo_data.get("price_data", {}).get("current_price", "N/A"),
                "analysis_date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                "sec_data": self._format_sec_data(sec_data),
                "yahoo_data": self._format_yahoo_data(yahoo_data),
                "fundamental_metrics": self._format_fundamental_metrics(fundamental_metrics),
                "industry_comparison": self._format_industry_comparison(industry_comparison),
                "format_instructions": self.output_parser.get_format_instructions()
            }
            
            # 执行LLM分析
            messages = self.analysis_prompt.format_messages(**analysis_data)
            response = await self.llm.agenerate([messages])
            
            # 解析结果
            result = self.output_parser.parse(response.generations[0][0].text)
            
            logger.info(f"基本面分析完成: {ticker}, 评分: {result.fundamental_score}")
            return result
            
        except Exception as e:
            logger.error(f"基本面分析失败: {e}")
            # 返回默认结果
            return self._create_fallback_result(ticker, str(e))
    
    async def _get_sec_data(self, ticker: str) -> Dict[str, Any]:
        """获取SEC Edgar数据"""
        try:
            return self.data_sources["sec_edgar"].get_company_facts(ticker)
        except Exception as e:
            logger.error(f"获取SEC数据失败: {e}")
            return {}
    
    async def _get_yahoo_data(self, ticker: str) -> Dict[str, Any]:
        """获取Yahoo Finance增强数据"""
        try:
            return self.data_sources["yahoo_enhanced"].get_enhanced_stock_data(ticker)
        except Exception as e:
            logger.error(f"获取Yahoo数据失败: {e}")
            return {}
    
    def _calculate_fundamental_metrics(
        self, 
        sec_data: Dict[str, Any], 
        yahoo_data: Dict[str, Any]
    ) -> FundamentalMetrics:
        """计算基本面指标"""
        try:
            metrics = FundamentalMetrics()
            
            # 从Yahoo数据提取基础指标
            basic_info = yahoo_data.get("basic_info", {})
            price_data = yahoo_data.get("price_data", {})
            financial_data = yahoo_data.get("financial_data", {})
            
            # 估值指标
            metrics.pe_ratio = basic_info.get("pe_ratio")
            metrics.pb_ratio = basic_info.get("pb_ratio")
            
            # 计算PS比率
            if price_data.get("current_price") and financial_data.get("revenue"):
                market_cap = basic_info.get("market_cap")
                if market_cap and financial_data.get("revenue"):
                    metrics.ps_ratio = market_cap / financial_data["revenue"]
            
            # 从SEC数据计算更精确的指标
            if sec_data:
                # ROE计算
                if sec_data.get("net_income") and sec_data.get("shareholders_equity"):
                    metrics.roe = sec_data["net_income"] / sec_data["shareholders_equity"]
                
                # ROA计算
                if sec_data.get("net_income") and sec_data.get("total_assets"):
                    metrics.roa = sec_data["net_income"] / sec_data["total_assets"]
                
                # 净利润率
                if sec_data.get("net_income") and sec_data.get("revenue"):
                    metrics.net_margin = sec_data["net_income"] / sec_data["revenue"]
                
                # 债务权益比
                if sec_data.get("total_debt") and sec_data.get("shareholders_equity"):
                    metrics.debt_to_equity = sec_data["total_debt"] / sec_data["shareholders_equity"]
            
            # 分红指标
            metrics.dividend_yield = basic_info.get("dividend_yield")
            
            # 计算数据完整性
            total_fields = 15  # 主要指标数量
            filled_fields = sum(1 for field in [
                metrics.pe_ratio, metrics.pb_ratio, metrics.ps_ratio,
                metrics.roe, metrics.roa, metrics.net_margin,
                metrics.debt_to_equity, metrics.dividend_yield
            ] if field is not None)
            
            metrics.data_completeness = filled_fields / total_fields
            metrics.last_updated = datetime.now().isoformat()
            metrics.data_sources = ["SEC Edgar", "Yahoo Finance"]
            
            return metrics
            
        except Exception as e:
            logger.error(f"计算基本面指标失败: {e}")
            return FundamentalMetrics()
    
    async def _get_industry_comparison(
        self, 
        ticker: str, 
        yahoo_data: Dict[str, Any]
    ) -> Dict[str, Any]:
        """获取行业对比数据"""
        try:
            sector = yahoo_data.get("basic_info", {}).get("sector", "")
            industry = yahoo_data.get("basic_info", {}).get("industry", "")
            
            # 这里可以扩展为获取同行业其他公司的数据进行对比
            # 目前返回基础的行业信息
            return {
                "sector": sector,
                "industry": industry,
                "comparison_note": "行业对比功能将在后续版本中完善"
            }
            
        except Exception as e:
            logger.error(f"获取行业对比数据失败: {e}")
            return {}
    
    def _format_sec_data(self, sec_data: Dict[str, Any]) -> str:
        """格式化SEC数据"""
        if not sec_data:
            return "SEC数据不可用"
        
        formatted = []
        formatted.append(f"数据源: {sec_data.get('data_source', 'SEC Edgar')}")
        formatted.append(f"更新时间: {sec_data.get('last_updated', 'N/A')}")
        
        if sec_data.get("revenue"):
            formatted.append(f"营业收入: ${sec_data['revenue']:,.0f}")
        
        if sec_data.get("net_income"):
            formatted.append(f"净利润: ${sec_data['net_income']:,.0f}")
        
        if sec_data.get("total_assets"):
            formatted.append(f"总资产: ${sec_data['total_assets']:,.0f}")
        
        if sec_data.get("shareholders_equity"):
            formatted.append(f"股东权益: ${sec_data['shareholders_equity']:,.0f}")
        
        if sec_data.get("total_debt"):
            formatted.append(f"总债务: ${sec_data['total_debt']:,.0f}")
        
        if sec_data.get("roe"):
            formatted.append(f"ROE: {sec_data['roe']:.2%}")
        
        if sec_data.get("net_margin"):
            formatted.append(f"净利润率: {sec_data['net_margin']:.2%}")
        
        return "\n".join(formatted)
    
    def _format_yahoo_data(self, yahoo_data: Dict[str, Any]) -> str:
        """格式化Yahoo数据"""
        if not yahoo_data:
            return "Yahoo Finance数据不可用"
        
        formatted = []
        formatted.append(f"数据源: {yahoo_data.get('data_source', 'Yahoo Finance')}")
        formatted.append(f"更新时间: {yahoo_data.get('last_updated', 'N/A')}")
        
        # 基础信息
        basic_info = yahoo_data.get("basic_info", {})
        if basic_info.get("company_name"):
            formatted.append(f"公司名称: {basic_info['company_name']}")
        
        if basic_info.get("sector"):
            formatted.append(f"行业: {basic_info['sector']}")
        
        if basic_info.get("market_cap"):
            formatted.append(f"市值: ${basic_info['market_cap']:,.0f}")
        
        if basic_info.get("pe_ratio"):
            formatted.append(f"PE比率: {basic_info['pe_ratio']:.2f}")
        
        if basic_info.get("pb_ratio"):
            formatted.append(f"PB比率: {basic_info['pb_ratio']:.2f}")
        
        # 价格数据
        price_data = yahoo_data.get("price_data", {})
        if price_data.get("current_price"):
            formatted.append(f"当前价格: ${price_data['current_price']:.2f}")
        
        if price_data.get("high_52w") and price_data.get("low_52w"):
            formatted.append(f"52周区间: ${price_data['low_52w']:.2f} - ${price_data['high_52w']:.2f}")
        
        return "\n".join(formatted)
    
    def _format_fundamental_metrics(self, metrics: FundamentalMetrics) -> str:
        """格式化基本面指标"""
        formatted = []
        formatted.append("=== 估值指标 ===")
        
        if metrics.pe_ratio:
            formatted.append(f"PE比率: {metrics.pe_ratio:.2f}")
        
        if metrics.pb_ratio:
            formatted.append(f"PB比率: {metrics.pb_ratio:.2f}")
        
        if metrics.ps_ratio:
            formatted.append(f"PS比率: {metrics.ps_ratio:.2f}")
        
        formatted.append("\n=== 盈利能力指标 ===")
        
        if metrics.roe:
            formatted.append(f"ROE: {metrics.roe:.2%}")
        
        if metrics.roa:
            formatted.append(f"ROA: {metrics.roa:.2%}")
        
        if metrics.net_margin:
            formatted.append(f"净利润率: {metrics.net_margin:.2%}")
        
        formatted.append("\n=== 财务健康指标 ===")
        
        if metrics.debt_to_equity:
            formatted.append(f"债务权益比: {metrics.debt_to_equity:.2f}")
        
        formatted.append(f"\n数据完整性: {metrics.data_completeness:.1%}")
        formatted.append(f"数据源: {', '.join(metrics.data_sources)}")
        
        return "\n".join(formatted)
    
    def _format_industry_comparison(self, comparison: Dict[str, Any]) -> str:
        """格式化行业对比数据"""
        if not comparison:
            return "行业对比数据不可用"
        
        formatted = []
        if comparison.get("sector"):
            formatted.append(f"所属板块: {comparison['sector']}")
        
        if comparison.get("industry"):
            formatted.append(f"细分行业: {comparison['industry']}")
        
        if comparison.get("comparison_note"):
            formatted.append(f"说明: {comparison['comparison_note']}")
        
        return "\n".join(formatted)
    
    def _create_fallback_result(self, ticker: str, error_msg: str) -> FundamentalAnalysisResult:
        """创建回退结果"""
        return FundamentalAnalysisResult(
            ticker=ticker.upper(),
            analysis_date=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            fundamental_score=50,
            valuation_score=50,
            profitability_score=50,
            financial_health_score=50,
            growth_score=50,
            recommendation="持有",
            confidence_level=0.3,
            key_strengths=["数据获取失败，无法评估"],
            key_weaknesses=["数据不完整"],
            risk_factors=["分析基于不完整数据"],
            valuation_analysis="由于数据获取失败，无法进行准确的估值分析。",
            profitability_analysis="由于数据获取失败，无法进行盈利能力分析。",
            financial_health_analysis="由于数据获取失败，无法进行财务健康分析。",
            growth_analysis="由于数据获取失败，无法进行增长分析。",
            target_price=None,
            price_range_low=None,
            price_range_high=None,
            data_quality_score=20,
            limitations=[f"数据获取错误: {error_msg}", "建议稍后重试或检查网络连接"]
        )
    
    async def batch_analyze(
        self, 
        tickers: List[str], 
        max_concurrent: int = 3
    ) -> Dict[str, FundamentalAnalysisResult]:
        """
        批量基本面分析
        
        @param {List[str]} tickers - 股票代码列表
        @param {int} max_concurrent - 最大并发数
        @returns {Dict[str, FundamentalAnalysisResult]} 分析结果字典
        """
        semaphore = asyncio.Semaphore(max_concurrent)
        
        async def analyze_single(ticker: str) -> Tuple[str, FundamentalAnalysisResult]:
            async with semaphore:
                result = await self.analyze_fundamentals(ticker)
                return ticker, result
        
        tasks = [analyze_single(ticker) for ticker in tickers]
        results = await asyncio.gather(*tasks, return_exceptions=True)
        
        # 处理结果
        analysis_results = {}
        for result in results:
            if isinstance(result, Exception):
                logger.error(f"批量分析中的错误: {result}")
                continue
            
            ticker, analysis = result
            analysis_results[ticker] = analysis
        
        logger.info(f"批量基本面分析完成: {len(analysis_results)}/{len(tickers)}个成功")
        return analysis_results
    
    def get_analysis_summary(self, result: FundamentalAnalysisResult) -> str:
        """
        获取分析摘要
        
        @param {FundamentalAnalysisResult} result - 分析结果
        @returns {str} 分析摘要
        """
        summary = f"""
=== {result.ticker} 基本面分析摘要 ===

综合评分: {result.fundamental_score}/100
投资建议: {result.recommendation}
置信度: {result.confidence_level:.1%}

分项评分:
- 估值: {result.valuation_score}/100
- 盈利能力: {result.profitability_score}/100  
- 财务健康: {result.financial_health_score}/100
- 增长潜力: {result.growth_score}/100

主要优势:
{chr(10).join(f'• {strength}' for strength in result.key_strengths)}

主要劣势:
{chr(10).join(f'• {weakness}' for weakness in result.key_weaknesses)}

风险因素:
{chr(10).join(f'• {risk}' for risk in result.risk_factors)}

数据质量: {result.data_quality_score}/100
分析时间: {result.analysis_date}
        """.strip()
        
        return summary


# 便捷函数
async def analyze_stock_fundamentals(
    ticker: str, 
    config: Optional[Dict[str, Any]] = None
) -> FundamentalAnalysisResult:
    """
    便捷的股票基本面分析函数
    
    @param {str} ticker - 股票代码
    @param {Optional[Dict[str, Any]]} config - 配置参数
    @returns {FundamentalAnalysisResult} 分析结果
    """
    analyst = FreeFundamentalsAnalyst(config)
    return await analyst.analyze_fundamentals(ticker)


if __name__ == "__main__":
    # 测试代码
    async def test_fundamentals_analyst():
        print("=== 免费基本面分析师测试 ===")
        
        try:
            # 创建分析师
            analyst = FreeFundamentalsAnalyst()
            
            # 测试单个股票分析
            print("测试AAPL基本面分析...")
            result = await analyst.analyze_fundamentals("AAPL")
            
            print(f"✅ 分析完成")
            print(f"   - 综合评分: {result.fundamental_score}/100")
            print(f"   - 投资建议: {result.recommendation}")
            print(f"   - 置信度: {result.confidence_level:.1%}")
            print(f"   - 数据质量: {result.data_quality_score}/100")
            
            # 打印详细摘要
            summary = analyst.get_analysis_summary(result)
            print("\n" + summary)
            
            # 测试批量分析
            print("\n测试批量分析...")
            batch_results = await analyst.batch_analyze(["AAPL", "MSFT", "GOOGL"])
            
            print(f"✅ 批量分析完成: {len(batch_results)}个股票")
            for ticker, result in batch_results.items():
                print(f"   - {ticker}: {result.fundamental_score}/100 ({result.recommendation})")
            
            print("\n🎉 免费基本面分析师测试完成！")
            
        except Exception as e:
            print(f"❌ 测试失败: {e}")
            raise
    
    # 运行测试
    asyncio.run(test_fundamentals_analyst())