"""训练配置管理

提供 TrainingConfig 配置类，使用 pydantic 进行参数验证。
"""

from dataclasses import dataclass
from typing import Any, Dict, List, Optional

from pydantic import Field, validator
from pydantic_settings import BaseSettings


@dataclass
class ProcessorConfig:
    """处理器配置"""

    name: str
    params: Dict[str, Any] = Field(default_factory=dict)


class TrainingConfig(BaseSettings):
    """训练配置类

    所有配置参数通过此类管理，支持 pydantic 验证。
    """

    # === 数据配置（必填）===
    feature_cols: List[str] = Field(..., min_items=1)  # 特征列名，至少一个
    target_col: str = "target"  # 目标变量列名
    date_col: str = "trade_date"  # 日期列名
    code_col: str = "ts_code"  # 股票代码列名

    # === 日期划分（必填）===
    train_start: str = Field(..., description="训练期开始 YYYYMMDD")
    train_end: str = Field(..., description="训练期结束 YYYYMMDD")
    test_start: str = Field(..., description="测试期开始 YYYYMMDD")
    test_end: str = Field(..., description="测试期结束 YYYYMMDD")

    # === 模型配置 ===
    model_type: str = "lightgbm"
    model_params: Dict[str, Any] = Field(default_factory=dict)

    # === 处理器配置 ===
    processors: List[ProcessorConfig] = Field(
        default_factory=lambda: [
            ProcessorConfig(name="winsorizer", params={"lower": 0.01, "upper": 0.99}),
            ProcessorConfig(name="cs_standard_scaler", params={}),
        ]
    )

    # === 持久化配置 ===
    persist_model: bool = False  # 默认不持久化
    model_save_path: Optional[str] = None  # 持久化路径

    # === 输出配置 ===
    output_dir: str = "output"
    save_predictions: bool = True

    @validator("train_start", "train_end", "test_start", "test_end")
    def validate_date_format(cls, v: str) -> str:
        """验证日期格式为 YYYYMMDD"""
        if not isinstance(v, str) or len(v) != 8:
            raise ValueError(f"日期必须是格式为 'YYYYMMDD' 的8位字符串，得到: {v}")
        try:
            int(v)
        except ValueError:
            raise ValueError(f"日期必须是数字字符串，得到: {v}")
        return v

    @validator("train_end")
    def validate_train_dates(cls, v: str, values: Dict[str, Any]) -> str:
        """验证训练日期范围"""
        if "train_start" in values and values["train_start"] > v:
            raise ValueError(
                f"train_start ({values['train_start']}) 必须早于或等于 train_end ({v})"
            )
        return v

    @validator("test_end")
    def validate_test_dates(cls, v: str, values: Dict[str, Any]) -> str:
        """验证测试日期范围"""
        if "test_start" in values and values["test_start"] > v:
            raise ValueError(
                f"test_start ({values['test_start']}) 必须早于或等于 test_end ({v})"
            )
        return v

    @validator("test_start")
    def validate_no_overlap(cls, v: str, values: Dict[str, Any]) -> str:
        """验证训练集和测试集不重叠"""
        if "train_end" in values and v <= values["train_end"]:
            raise ValueError(
                f"测试集开始日期 ({v}) 必须晚于训练集结束日期 ({values['train_end']})，"
                "以确保训练集和测试集不重叠"
            )
        return v

    class Config:
        """Pydantic 配置"""

        env_prefix = "TRAINING_"  # 环境变量前缀
        env_nested_delimiter = "__"
