#!/usr/bin/env python3
"""
TradingAgents 混合版本主程序
============================

混合版本特性：
- 🆓 免费数据源优先（SEC Edgar + Alpha Vantage + Yahoo Finance）
- 💰 付费数据源fallback（FinnHub）
- 🧠 智能数据源切换
- 📊 实时成本监控
- 🔄 自适应配置调整

预估成本：$10-40/月（相比原版$197/月节省85%）

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

用法示例：
    python main_hybrid.py NVDA --config balanced
    python main_hybrid.py AAPL --config cost_optimized
    python main_hybrid.py TSLA --config quality_first
"""

import os
import sys
import time
import argparse
import logging
from datetime import datetime
from typing import Dict, Any, Optional
from pathlib import Path

# 添加项目根目录到Python路径
sys.path.insert(0, str(Path(__file__).parent))

# 导入核心模块
from tradingagents.hybrid_config import (
    create_hybrid_config, 
    list_available_configs, 
    print_all_configs,
    HybridConfigManager
)
from tradingagents.dataflows.free_alternatives import FreeDataManager
from tradingagents.graph.graph import create_graph
from tradingagents.agents.state import AgentState

# 设置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('logs/hybrid_trading.log'),
        logging.StreamHandler(sys.stdout)
    ]
)
logger = logging.getLogger(__name__)

class HybridTradingEngine:
    """
    混合版本交易引擎
    
    @description 整合免费和付费数据源的智能交易分析引擎
    @version MVP-1.0
    """
    
    def __init__(self, config_name: str = "balanced"):
        """
        初始化混合交易引擎
        
        @param {str} config_name - 配置方案名称
        """
        self.config_manager = create_hybrid_config(config_name)
        self.free_data_manager = FreeDataManager(
            alpha_vantage_key=self.config_manager.config.alpha_vantage_key
        )
        self.start_time = time.time()
        
        # 确保日志目录存在
        os.makedirs("logs", exist_ok=True)
        
        logger.info(f"混合交易引擎已初始化，配置方案: {config_name}")
        self.config_manager.print_config_summary()
    
    def analyze_stock(self, symbol: str, enable_reasoning: bool = True) -> Dict[str, Any]:
        """
        分析股票（混合数据源版本）
        
        @param {str} symbol - 股票代码
        @param {bool} enable_reasoning - 是否启用推理模式
        @returns {Dict[str, Any]} 分析结果
        """
        start_time = time.time()
        logger.info(f"🚀 开始分析股票: {symbol}")
        
        try:
            # 1. 获取综合数据（免费数据源）
            logger.info("📊 获取免费数据源...")
            data_result = self._get_comprehensive_data(symbol)
            
            if data_result.get('error'):
                logger.error(f"数据获取失败: {data_result['error']}")
                return {
                    'symbol': symbol,
                    'status': 'error',
                    'error': data_result['error'],
                    'timestamp': datetime.now().isoformat()
                }
            
            # 2. 构建分析状态
            logger.info("🧠 构建分析状态...")
            state = self._build_analysis_state(symbol, data_result)
            
            # 3. 执行分析流程
            logger.info("⚡ 执行分析流程...")
            analysis_result = self._run_analysis_pipeline(state, enable_reasoning)
            
            # 4. 处理结果
            response_time = time.time() - start_time
            final_result = self._process_analysis_result(
                symbol, analysis_result, data_result, response_time
            )
            
            # 5. 更新运行时统计
            self._update_runtime_stats(True, response_time, False)
            
            logger.info(f"✅ 股票分析完成: {symbol} (耗时: {response_time:.2f}秒)")
            return final_result
            
        except Exception as e:
            response_time = time.time() - start_time
            logger.error(f"❌ 股票分析失败: {symbol}, 错误: {e}")
            
            # 更新失败统计
            self._update_runtime_stats(False, response_time, False)
            
            return {
                'symbol': symbol,
                'status': 'error',
                'error': str(e),
                'response_time': response_time,
                'timestamp': datetime.now().isoformat()
            }
    
    def _get_comprehensive_data(self, symbol: str) -> Dict[str, Any]:
        """获取综合数据（优先免费源）"""
        try:
            # 首先尝试免费数据源
            data = self.free_data_manager.get_comprehensive_data(symbol)
            
            if data and not data.get('error'):
                logger.info(f"免费数据源获取成功: {', '.join(data.get('data_sources', []))}")
                return data
            
            # 如果免费源失败，尝试降级模式
            logger.warning("免费数据源失败，尝试降级模式...")
            fallback_data = self.free_data_manager.get_fallback_data(symbol)
            
            if fallback_data and not fallback_data.get('error'):
                logger.info("降级模式数据获取成功")
                return fallback_data
            
            # 如果启用付费fallback，可以在这里添加FinnHub调用
            if self.config_manager.should_enable_fallback("fundamentals"):
                logger.info("尝试付费数据源fallback...")
                # 这里可以集成原有的FinnHub逻辑
                # 暂时返回错误，后续可以完善
                return {'error': 'All data sources failed, paid fallback not implemented yet'}
            
            return {'error': 'All free data sources failed'}
            
        except Exception as e:
            logger.error(f"综合数据获取异常: {e}")
            return {'error': str(e)}
    
    def _build_analysis_state(self, symbol: str, data: Dict[str, Any]) -> AgentState:
        """构建分析状态"""
        # 转换数据格式以适配现有的分析流程
        yahoo_data = data.get('yahoo_finance', {})
        sec_data = data.get('sec_edgar', {})
        av_data = data.get('alpha_vantage', {})
        news_data = data.get('news', [])
        
        # 构建统一的数据格式
        price_data = yahoo_data.get('price_data', {})
        basic_info = yahoo_data.get('basic_info', {})
        
        state = AgentState(
            ticker=symbol,
            company_of_interest=symbol,
            trade_date=datetime.now().strftime('%Y-%m-%d'),
            
            # 价格数据
            current_price=price_data.get('current_price'),
            price_change_24h=price_data.get('price_change_52w', 0),  # 使用52周变化作为替代
            
            # 基本信息
            company_name=basic_info.get('company_name', ''),
            sector=basic_info.get('sector', ''),
            market_cap=basic_info.get('market_cap'),
            
            # 财务数据（优先使用SEC数据）
            revenue=sec_data.get('revenue') or basic_info.get('revenue'),
            net_income=sec_data.get('net_income'),
            total_assets=sec_data.get('total_assets'),
            pe_ratio=basic_info.get('trailing_pe'),
            
            # 技术指标
            rsi=yahoo_data.get('technical_indicators', {}).get('rsi'),
            sma_20=yahoo_data.get('technical_indicators', {}).get('sma_20'),
            sma_50=yahoo_data.get('technical_indicators', {}).get('sma_50'),
            
            # 新闻数据
            recent_news=news_data[:5],  # 取前5条新闻
            
            # 分析师数据
            analyst_rating=yahoo_data.get('analyst_data', {}).get('recommendation_mean'),
            target_price=yahoo_data.get('analyst_data', {}).get('target_mean_price'),
            
            # 元数据
            data_sources=data.get('data_sources', []),
            analysis_timestamp=datetime.now().isoformat(),
            
            # 配置信息
            config_name=self.config_manager.config_name,
            using_free_sources=True,
            
            # 兼容性字段 - 初始化为空避免KeyError
            investment_debate_state={
                'bull_history': '',
                'bear_history': '',
                'history': '',
                'current_response': '',
                'judge_decision': '',
                'count': 0
            },
            risk_debate_state={
                'risky_history': '',
                'safe_history': '',
                'neutral_history': '',
                'history': '',
                'latest_speaker': '',
                'current_risky_response': '',
                'current_safe_response': '',
                'current_neutral_response': '',
                'judge_decision': '',
                'count': 0
            },
            market_report='',
            sentiment_report='',
            news_report='',
            fundamentals_report='',
            investment_plan='',
            trader_investment_plan='',
            final_trade_decision=''
        )
        
        return state
    
    def _run_analysis_pipeline(self, state: AgentState, enable_reasoning: bool) -> Dict[str, Any]:
        """运行分析管道"""
        try:
            # 使用现有的图结构
            graph = create_graph()
            
            # 设置配置
            config = {
                "configurable": {
                    "deep_think_llm": "gpt-4o-mini",
                    "quick_think_llm": "gpt-4o-mini",
                    "enable_reasoning": enable_reasoning,
                    "hybrid_mode": True,
                    "config_name": self.config_manager.config_name
                }
            }
            
            # 执行分析
            result = graph.invoke(state, config)
            return result
            
        except Exception as e:
            logger.error(f"分析管道执行失败: {e}")
            raise
    
    def _process_analysis_result(
        self, 
        symbol: str, 
        analysis_result: Dict[str, Any], 
        data_result: Dict[str, Any], 
        response_time: float
    ) -> Dict[str, Any]:
        """处理分析结果"""
        
        # 提取关键决策信息
        final_decision = analysis_result.get('final_decision', 'HOLD')
        confidence = analysis_result.get('confidence', 0.5)
        reasoning = analysis_result.get('reasoning', '')
        
        # 构建最终结果
        result = {
            'symbol': symbol,
            'status': 'success',
            'timestamp': datetime.now().isoformat(),
            'response_time': response_time,
            
            # 核心决策
            'decision': final_decision,
            'confidence': confidence,
            'reasoning': reasoning,
            
            # 数据源信息
            'data_sources': data_result.get('data_sources', []),
            'config_name': self.config_manager.config_name,
            'using_free_sources': True,
            
            # 成本信息
            'estimated_cost': self._calculate_analysis_cost(),
            
            # 完整分析结果
            'full_analysis': analysis_result,
            
            # 性能统计
            'performance_stats': self.config_manager.runtime_stats
        }
        
        return result
    
    def _update_runtime_stats(self, success: bool, response_time: float, used_fallback: bool):
        """更新运行时统计"""
        self.config_manager.update_runtime_stats(success, response_time, used_fallback)
        
        # 每10次分析后自适应调整配置
        if self.config_manager.runtime_stats["daily_api_calls"] % 10 == 0:
            self.config_manager.adapt_config_based_on_performance()
    
    def _calculate_analysis_cost(self) -> float:
        """计算单次分析成本"""
        # 基础OpenAI API成本（估算）
        base_cost = 0.01  # 约1美分
        
        # Alpha Vantage成本（如果使用）
        if self.config_manager.can_use_alpha_vantage():
            av_cost = 0.002  # 非常低的成本
            base_cost += av_cost
        
        # FinnHub成本（如果使用fallback）
        if self.config_manager.runtime_stats.get("fallback_usage_rate", 0) > 0:
            fallback_cost = 0.05  # 付费API成本
            base_cost += fallback_cost
        
        return base_cost
    
    def batch_analyze(self, symbols: list, enable_reasoning: bool = True) -> Dict[str, Any]:
        """批量分析股票"""
        logger.info(f"🔄 开始批量分析 {len(symbols)} 只股票")
        
        results = {}
        total_cost = 0.0
        
        for i, symbol in enumerate(symbols, 1):
            logger.info(f"[{i}/{len(symbols)}] 分析 {symbol}")
            
            result = self.analyze_stock(symbol, enable_reasoning)
            results[symbol] = result
            
            if result.get('estimated_cost'):
                total_cost += result['estimated_cost']
            
            # 避免API限制
            time.sleep(self.config_manager.config.request_delay_seconds)
        
        # 批量分析摘要
        successful = sum(1 for r in results.values() if r.get('status') == 'success')
        failed = len(symbols) - successful
        
        summary = {
            'batch_analysis': True,
            'total_symbols': len(symbols),
            'successful': successful,
            'failed': failed,
            'total_cost': total_cost,
            'avg_cost_per_stock': total_cost / len(symbols) if symbols else 0,
            'config_name': self.config_manager.config_name,
            'timestamp': datetime.now().isoformat(),
            'results': results
        }
        
        logger.info(f"✅ 批量分析完成: {successful}/{len(symbols)} 成功，总成本: ${total_cost:.4f}")
        
        return summary
    
    def get_engine_status(self) -> Dict[str, Any]:
        """获取引擎状态"""
        runtime = time.time() - self.start_time
        
        return {
            'engine_status': 'running',
            'runtime_seconds': runtime,
            'config': self.config_manager.export_config(),
            'performance_stats': self.config_manager.runtime_stats,
            'data_sources_priority': {
                'fundamentals': self.config_manager.get_data_source_priority('fundamentals'),
                'news': self.config_manager.get_data_source_priority('news'),
                'technical': self.config_manager.get_data_source_priority('technical')
            }
        }


def main():
    """主程序入口"""
    parser = argparse.ArgumentParser(
        description="TradingAgents 混合版本 - 智能股票分析引擎",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
配置方案:
  cost_optimized  - 成本优化($10-20/月)
  balanced        - 平衡模式($20-40/月) [默认]
  quality_first   - 质量优先($40-80/月)
  development     - 开发模式($10-15/月)

使用示例:
  python main_hybrid.py NVDA
  python main_hybrid.py AAPL --config cost_optimized
  python main_hybrid.py TSLA MSFT GOOGL --batch
  python main_hybrid.py --list-configs
  python main_hybrid.py --status
        """
    )
    
    parser.add_argument(
        'symbols', 
        nargs='*', 
        help='股票代码列表'
    )
    
    parser.add_argument(
        '--config', 
        choices=list_available_configs(),
        default='balanced',
        help='配置方案 (默认: balanced)'
    )
    
    parser.add_argument(
        '--batch', 
        action='store_true',
        help='批量分析模式'
    )
    
    parser.add_argument(
        '--no-reasoning', 
        action='store_true',
        help='禁用推理模式（更快）'
    )
    
    parser.add_argument(
        '--list-configs', 
        action='store_true',
        help='列出所有配置方案'
    )
    
    parser.add_argument(
        '--status', 
        action='store_true',
        help='显示引擎状态'
    )
    
    parser.add_argument(
        '--verbose', 
        action='store_true',
        help='详细输出模式'
    )
    
    args = parser.parse_args()
    
    # 设置日志级别
    if args.verbose:
        logging.getLogger().setLevel(logging.DEBUG)
    
    # 处理配置列表请求
    if args.list_configs:
        print_all_configs()
        return
    
    # 创建混合引擎
    try:
        engine = HybridTradingEngine(args.config)
    except Exception as e:
        logger.error(f"引擎初始化失败: {e}")
        sys.exit(1)
    
    # 处理状态请求
    if args.status:
        status = engine.get_engine_status()
        print("\n🔍 引擎状态:")
        print(f"运行时间: {status['runtime_seconds']:.2f}秒")
        print(f"配置方案: {status['config']['config_name']}")
        print(f"API调用次数: {status['performance_stats']['daily_api_calls']}")
        print(f"免费源成功率: {status['performance_stats']['free_success_rate']:.2%}")
        return
    
    # 检查股票代码
    if not args.symbols:
        parser.print_help()
        return
    
    # 执行分析
    try:
        if args.batch and len(args.symbols) > 1:
            # 批量分析
            result = engine.batch_analyze(args.symbols, not args.no_reasoning)
            
            print(f"\n📊 批量分析结果:")
            print(f"总计: {result['total_symbols']} 只股票")
            print(f"成功: {result['successful']} 只")
            print(f"失败: {result['failed']} 只")
            print(f"总成本: ${result['total_cost']:.4f}")
            print(f"平均成本: ${result['avg_cost_per_stock']:.4f}/股")
            
            # 显示各股票结果
            for symbol, stock_result in result['results'].items():
                if stock_result.get('status') == 'success':
                    decision = stock_result.get('decision', 'UNKNOWN')
                    confidence = stock_result.get('confidence', 0) * 100
                    print(f"  {symbol}: {decision} (置信度: {confidence:.1f}%)")
                else:
                    print(f"  {symbol}: 分析失败")
        
        else:
            # 单个分析
            symbol = args.symbols[0]
            result = engine.analyze_stock(symbol, not args.no_reasoning)
            
            if result.get('status') == 'success':
                print(f"\n🎯 {symbol} 分析结果:")
                print(f"决策: {result.get('decision', 'UNKNOWN')}")
                print(f"置信度: {result.get('confidence', 0) * 100:.1f}%")
                print(f"数据源: {', '.join(result.get('data_sources', []))}")
                print(f"分析成本: ${result.get('estimated_cost', 0):.4f}")
                print(f"响应时间: {result.get('response_time', 0):.2f}秒")
                
                if args.verbose and result.get('reasoning'):
                    print(f"\n💭 分析理由:\n{result['reasoning']}")
            
            else:
                print(f"\n❌ {symbol} 分析失败: {result.get('error', '未知错误')}")
                sys.exit(1)
    
    except KeyboardInterrupt:
        logger.info("用户中断分析")
        sys.exit(0)
    except Exception as e:
        logger.error(f"分析过程中发生错误: {e}")
        sys.exit(1)


if __name__ == "__main__":
    main() 