"""
美股专用配置模块

该模块为美股分析提供优化的配置参数：
- 智能缓存策略（考虑市场时间）
- 数据源优先级和重试机制
- 美股市场时间处理
- 成本优化配置

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

import os
import pytz
from typing import Dict, Any, Optional, List, Tuple
from dataclasses import dataclass, field
from datetime import datetime, time, timedelta
import logging
from enum import Enum

logger = logging.getLogger(__name__)


class MarketStatus(Enum):
    """市场状态枚举"""
    OPEN = "open"
    CLOSED = "closed"
    PRE_MARKET = "pre_market"
    AFTER_HOURS = "after_hours"
    WEEKEND = "weekend"
    HOLIDAY = "holiday"


@dataclass
class DataSourceConfig:
    """数据源配置"""
    name: str
    enabled: bool
    priority: int
    timeout: int
    max_retries: int
    retry_delay: float
    daily_limit: Optional[int] = None
    cost_per_call: float = 0.0


@dataclass
class CacheConfig:
    """缓存配置"""
    ttl_market_open: int  # 市场开放时缓存时间（分钟）
    ttl_market_closed: int  # 市场关闭时缓存时间（小时）
    ttl_weekend: int  # 周末缓存时间（小时）
    max_size_mb: int  # 最大缓存大小
    cleanup_interval: int  # 清理间隔（小时）


@dataclass
class USStockConfig:
    """
    美股专用配置类
    
    @description 管理美股分析的所有配置参数
    """
    
    # API配置
    alpha_vantage_api_key: str = field(default_factory=lambda: os.getenv("ALPHA_VANTAGE_API_KEY", ""))
    finnhub_api_key: str = field(default_factory=lambda: os.getenv("FINNHUB_API_KEY", ""))
    
    # 数据源配置
    data_sources: List[DataSourceConfig] = field(default_factory=list)
    
    # 缓存配置
    cache_config: CacheConfig = field(default_factory=lambda: CacheConfig(
        ttl_market_open=5,     # 市场开放时5分钟缓存
        ttl_market_closed=4,   # 市场关闭时4小时缓存
        ttl_weekend=24,        # 周末24小时缓存
        max_size_mb=1000,      # 1GB缓存限制
        cleanup_interval=6     # 6小时清理一次
    ))
    
    # 市场时间配置
    market_timezone: str = "America/New_York"
    market_open_time: time = time(9, 30)
    market_close_time: time = time(16, 0)
    pre_market_start: time = time(4, 0)
    after_hours_end: time = time(20, 0)
    
    # 重试配置
    max_retries: int = 3
    retry_backoff_factor: float = 2.0
    retry_on_status_codes: List[int] = field(default_factory=lambda: [429, 500, 502, 503, 504])
    
    # 请求限制
    yahoo_max_requests_per_hour: int = 120
    yahoo_min_interval_seconds: int = 3
    alpha_vantage_daily_limit: int = 450
    
    # 数据质量控制
    min_data_sources: int = 1
    require_price_data: bool = True
    max_data_age_hours: int = 24
    
    # 新闻配置
    news_max_articles: int = 20
    news_max_age_days: int = 7
    enable_sentiment_analysis: bool = True
    
    # 成本控制
    max_monthly_cost: float = 50.0
    cost_alert_threshold: float = 0.8
    
    # 调试和监控
    enable_performance_logging: bool = True
    log_level: str = "INFO"
    enable_metrics: bool = True
    
    def __post_init__(self):
        """初始化后处理"""
        if not self.data_sources:
            self._init_default_data_sources()
        
        # 验证配置
        self._validate_config()
        
        logger.info("美股配置初始化完成")
    
    def _init_default_data_sources(self):
        """初始化默认数据源配置"""
        self.data_sources = [
            DataSourceConfig(
                name="alpha_vantage",
                enabled=bool(self.alpha_vantage_api_key),
                priority=1,
                timeout=30,
                max_retries=3,
                retry_delay=2.0,
                daily_limit=450,
                cost_per_call=0.01
            ),
            DataSourceConfig(
                name="yahoo_finance",
                enabled=True,
                priority=2,
                timeout=30,
                max_retries=3,
                retry_delay=3.0,
                daily_limit=120,  # 每小时限制
                cost_per_call=0.0
            ),
            DataSourceConfig(
                name="sec_edgar",
                enabled=True,
                priority=3,
                timeout=30,
                max_retries=2,
                retry_delay=1.0,
                cost_per_call=0.0
            ),
            DataSourceConfig(
                name="finnhub",
                enabled=bool(self.finnhub_api_key),
                priority=4,
                timeout=30,
                max_retries=2,
                retry_delay=1.0,
                cost_per_call=0.02
            )
        ]
    
    def _validate_config(self):
        """验证配置参数"""
        errors = []
        
        # 验证API密钥
        if not self.alpha_vantage_api_key and not self.finnhub_api_key:
            logger.warning("建议配置至少一个付费API密钥以获得更好的数据质量")
        
        # 验证缓存配置
        if self.cache_config.ttl_market_open <= 0:
            errors.append("市场开放时缓存时间必须大于0")
        
        if self.cache_config.max_size_mb <= 0:
            errors.append("缓存大小限制必须大于0")
        
        # 验证重试配置
        if self.max_retries < 0:
            errors.append("重试次数不能为负数")
        
        if self.retry_backoff_factor <= 0:
            errors.append("重试退避因子必须大于0")
        
        # 验证限制配置
        if self.yahoo_max_requests_per_hour <= 0:
            errors.append("Yahoo Finance请求限制必须大于0")
        
        if self.alpha_vantage_daily_limit <= 0:
            errors.append("Alpha Vantage日限制必须大于0")
        
        if errors:
            raise ValueError(f"配置验证失败: {'; '.join(errors)}")
    
    def get_market_status(self, dt: Optional[datetime] = None) -> MarketStatus:
        """
        获取当前市场状态
        
        @param {Optional[datetime]} dt - 指定时间，默认为当前时间
        @returns {MarketStatus} 市场状态
        """
        if dt is None:
            dt = datetime.now()
        
        # 转换到美股时区（简化版，避免pytz依赖问题）
        try:
            us_tz = pytz.timezone(self.market_timezone)
            if dt.tzinfo is None:
                dt = dt.replace(tzinfo=pytz.UTC)
            us_time = dt.astimezone(us_tz)
        except Exception:
            # 如果时区转换失败，使用当前时间
            us_time = datetime.now()
        
        # 检查是否是周末
        if us_time.weekday() >= 5:  # 周六或周日
            return MarketStatus.WEEKEND
        
        # 检查是否是节假日（简化版）
        if self._is_market_holiday(us_time):
            return MarketStatus.HOLIDAY
        
        current_time = us_time.time()
        
        # 判断市场状态
        if self.market_open_time <= current_time <= self.market_close_time:
            return MarketStatus.OPEN
        elif self.pre_market_start <= current_time < self.market_open_time:
            return MarketStatus.PRE_MARKET
        elif self.market_close_time < current_time <= self.after_hours_end:
            return MarketStatus.AFTER_HOURS
        else:
            return MarketStatus.CLOSED
    
    def _is_market_holiday(self, dt: datetime) -> bool:
        """
        检查是否是市场节假日（简化版）
        
        @param {datetime} dt - 检查的日期
        @returns {bool} 是否是节假日
        """
        # 这里可以添加美股节假日的完整列表
        # 目前只检查一些主要节假日
        month, day = dt.month, dt.day
        
        # 新年
        if month == 1 and day == 1:
            return True
        
        # 圣诞节
        if month == 12 and day == 25:
            return True
        
        # 独立日
        if month == 7 and day == 4:
            return True
        
        return False
    
    def get_cache_ttl(self, market_status: Optional[MarketStatus] = None) -> int:
        """
        根据市场状态获取缓存TTL（秒）
        
        @param {Optional[MarketStatus]} market_status - 市场状态
        @returns {int} 缓存TTL（秒）
        """
        if market_status is None:
            market_status = self.get_market_status()
        
        if market_status == MarketStatus.OPEN:
            return self.cache_config.ttl_market_open * 60  # 转换为秒
        elif market_status in [MarketStatus.WEEKEND, MarketStatus.HOLIDAY]:
            return self.cache_config.ttl_weekend * 3600  # 转换为秒
        else:
            return self.cache_config.ttl_market_closed * 3600  # 转换为秒
    
    def get_data_source_by_name(self, name: str) -> Optional[DataSourceConfig]:
        """
        根据名称获取数据源配置
        
        @param {str} name - 数据源名称
        @returns {Optional[DataSourceConfig]} 数据源配置
        """
        for source in self.data_sources:
            if source.name == name:
                return source
        return None
    
    def get_enabled_data_sources(self) -> List[DataSourceConfig]:
        """
        获取启用的数据源列表（按优先级排序）
        
        @returns {List[DataSourceConfig]} 启用的数据源列表
        """
        enabled_sources = [source for source in self.data_sources if source.enabled]
        return sorted(enabled_sources, key=lambda x: x.priority)
    
    def get_estimated_monthly_cost(self) -> float:
        """
        估算月度成本
        
        @returns {float} 预估月度成本（美元）
        """
        total_cost = 0.0
        
        for source in self.data_sources:
            if source.enabled and source.daily_limit and source.cost_per_call > 0:
                # 假设每天使用80%的限额
                daily_calls = source.daily_limit * 0.8
                monthly_calls = daily_calls * 30
                monthly_cost = monthly_calls * source.cost_per_call
                total_cost += monthly_cost
        
        return total_cost
    
    def is_cost_acceptable(self) -> bool:
        """
        检查成本是否可接受
        
        @returns {bool} 成本是否在预算内
        """
        estimated_cost = self.get_estimated_monthly_cost()
        return estimated_cost <= self.max_monthly_cost
    
    def should_alert_cost(self) -> bool:
        """
        是否应该发出成本警告
        
        @returns {bool} 是否需要成本警告
        """
        estimated_cost = self.get_estimated_monthly_cost()
        threshold_cost = self.max_monthly_cost * self.cost_alert_threshold
        return estimated_cost >= threshold_cost
    
    def get_retry_delay(self, attempt: int) -> float:
        """
        计算重试延迟时间
        
        @param {int} attempt - 重试次数（从1开始）
        @returns {float} 延迟时间（秒）
        """
        if attempt <= 0:
            return 0
        
        base_delay = 1.0
        return base_delay * (self.retry_backoff_factor ** (attempt - 1))
    
    def get_optimal_data_sources_for_symbol(self, symbol: str) -> List[str]:
        """
        为特定股票获取最优数据源
        
        @param {str} symbol - 股票代码
        @returns {List[str]} 优化的数据源名称列表
        """
        # 基本优先级
        optimal_sources = []
        
        # Alpha Vantage对所有美股都很好
        if self.get_data_source_by_name("alpha_vantage") and self.get_data_source_by_name("alpha_vantage").enabled:
            optimal_sources.append("alpha_vantage")
        
        # Yahoo Finance作为备用
        if self.get_data_source_by_name("yahoo_finance") and self.get_data_source_by_name("yahoo_finance").enabled:
            optimal_sources.append("yahoo_finance")
        
        # SEC Edgar用于基本面数据
        if self.get_data_source_by_name("sec_edgar") and self.get_data_source_by_name("sec_edgar").enabled:
            optimal_sources.append("sec_edgar")
        
        return optimal_sources
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典格式"""
        return {
            "alpha_vantage_enabled": bool(self.alpha_vantage_api_key),
            "finnhub_enabled": bool(self.finnhub_api_key),
            "data_sources": [
                {
                    "name": source.name,
                    "enabled": source.enabled,
                    "priority": source.priority,
                    "daily_limit": source.daily_limit,
                    "cost_per_call": source.cost_per_call
                }
                for source in self.data_sources
            ],
            "cache_config": {
                "ttl_market_open": self.cache_config.ttl_market_open,
                "ttl_market_closed": self.cache_config.ttl_market_closed,
                "ttl_weekend": self.cache_config.ttl_weekend,
                "max_size_mb": self.cache_config.max_size_mb
            },
            "market_status": self.get_market_status().value,
            "estimated_monthly_cost": self.get_estimated_monthly_cost(),
            "cost_acceptable": self.is_cost_acceptable(),
            "cost_alert": self.should_alert_cost()
        }
    
    @classmethod
    def from_env(cls) -> 'USStockConfig':
        """从环境变量创建配置"""
        config = cls()
        
        # 从环境变量覆盖配置
        if os.getenv("US_STOCK_MAX_MONTHLY_COST"):
            try:
                config.max_monthly_cost = float(os.getenv("US_STOCK_MAX_MONTHLY_COST"))
            except ValueError:
                logger.warning("无效的US_STOCK_MAX_MONTHLY_COST值")
        
        if os.getenv("US_STOCK_CACHE_TTL_OPEN"):
            try:
                config.cache_config.ttl_market_open = int(os.getenv("US_STOCK_CACHE_TTL_OPEN"))
            except ValueError:
                logger.warning("无效的US_STOCK_CACHE_TTL_OPEN值")
        
        if os.getenv("US_STOCK_LOG_LEVEL"):
            config.log_level = os.getenv("US_STOCK_LOG_LEVEL").upper()
        
        return config


class USStockConfigManager:
    """美股配置管理器"""
    
    def __init__(self, config: Optional[USStockConfig] = None):
        """
        初始化配置管理器
        
        @param {Optional[USStockConfig]} config - 配置对象
        """
        self.config = config or USStockConfig.from_env()
        self._runtime_stats = {
            "total_requests": 0,
            "successful_requests": 0,
            "failed_requests": 0,
            "cost_today": 0.0,
            "last_reset": datetime.now().date()
        }
        
        logger.info("美股配置管理器初始化完成")
    
    def get_config(self) -> USStockConfig:
        """获取配置"""
        return self.config
    
    def update_request_stats(self, source: str, success: bool, cost: float = 0.0):
        """
        更新请求统计
        
        @param {str} source - 数据源名称
        @param {bool} success - 是否成功
        @param {float} cost - 请求成本
        """
        # 检查是否需要重置日统计
        today = datetime.now().date()
        if today != self._runtime_stats["last_reset"]:
            self._runtime_stats["cost_today"] = 0.0
            self._runtime_stats["last_reset"] = today
        
        self._runtime_stats["total_requests"] += 1
        if success:
            self._runtime_stats["successful_requests"] += 1
        else:
            self._runtime_stats["failed_requests"] += 1
        
        self._runtime_stats["cost_today"] += cost
    
    def get_runtime_stats(self) -> Dict[str, Any]:
        """获取运行时统计"""
        return {
            **self._runtime_stats,
            "success_rate": self._runtime_stats["successful_requests"] / max(1, self._runtime_stats["total_requests"]),
            "estimated_monthly_cost": self.config.get_estimated_monthly_cost(),
            "current_market_status": self.config.get_market_status().value
        }
    
    def should_use_source(self, source_name: str) -> bool:
        """
        判断是否应该使用某个数据源
        
        @param {str} source_name - 数据源名称
        @returns {bool} 是否应该使用
        """
        source = self.config.get_data_source_by_name(source_name)
        if not source or not source.enabled:
            return False
        
        # 检查成本限制
        if self._runtime_stats["cost_today"] >= self.config.max_monthly_cost / 30:
            logger.warning(f"日成本限制已达到，跳过付费源: {source_name}")
            return source.cost_per_call == 0.0
        
        return True
    
    def get_optimal_cache_strategy(self, symbol: str) -> Dict[str, Any]:
        """
        获取最优缓存策略
        
        @param {str} symbol - 股票代码
        @returns {Dict[str, Any]} 缓存策略
        """
        market_status = self.config.get_market_status()
        ttl = self.config.get_cache_ttl(market_status)
        
        return {
            "ttl_seconds": ttl,
            "market_status": market_status.value,
            "cache_key_prefix": f"us_stock_{symbol}",
            "enable_aggressive_caching": market_status in [MarketStatus.WEEKEND, MarketStatus.HOLIDAY, MarketStatus.CLOSED]
        }


# 全局配置实例
try:
    us_stock_config = USStockConfig.from_env()
    us_stock_config_manager = USStockConfigManager(us_stock_config)
except Exception as e:
    logger.error(f"美股配置初始化失败: {e}")
    # 创建默认配置
    us_stock_config = USStockConfig()
    us_stock_config_manager = USStockConfigManager(us_stock_config)


def get_us_stock_config() -> USStockConfig:
    """获取美股配置实例"""
    return us_stock_config


def get_us_stock_config_manager() -> USStockConfigManager:
    """获取美股配置管理器实例"""
    return us_stock_config_manager


def create_optimized_config_for_symbol(symbol: str) -> Dict[str, Any]:
    """
    为特定股票创建优化配置
    
    @param {str} symbol - 股票代码
    @returns {Dict[str, Any]} 优化配置
    """
    config = get_us_stock_config()
    manager = get_us_stock_config_manager()
    
    return {
        "symbol": symbol,
        "data_sources": config.get_optimal_data_sources_for_symbol(symbol),
        "cache_strategy": manager.get_optimal_cache_strategy(symbol),
        "market_status": config.get_market_status().value,
        "retry_config": {
            "max_retries": config.max_retries,
            "backoff_factor": config.retry_backoff_factor
        },
        "cost_info": {
            "estimated_monthly": config.get_estimated_monthly_cost(),
            "daily_budget": config.max_monthly_cost / 30,
            "cost_acceptable": config.is_cost_acceptable()
        }
    } 