"""因子元数据字段校验器。

提供核心字段的校验逻辑，支持扩展字段的自由定义。
"""

from typing import Any, Dict, List, Set

from src.factors.metadata.exceptions import ValidationError


class FactorValidator:
    """因子字段校验器。

    校验核心字段的存在性和类型，允许任意扩展字段。

    核心字段:
        - factor_id (str): 全局唯一标识符
        - name (str): 可读短名称
        - desc (str): 详细描述
        - dsl (str): DSL计算公式

    Attributes:
        required_fields: 必需字段集合
    """

    REQUIRED_FIELDS: Set[str] = {"factor_id", "name", "desc", "dsl"}

    @classmethod
    def validate(cls, factor_dict: Dict[str, Any]) -> None:
        """校验因子字典。

        检查是否包含所有核心字段，以及字段类型是否正确。

        Args:
            factor_dict: 待校验的因子字典

        Raises:
            ValidationError: 当缺少核心字段或字段类型错误时

        Example:
            >>> factor = {
            ...     "factor_id": "F_001",
            ...     "name": "mom_5d",
            ...     "desc": "5日动量",
            ...     "dsl": "cs_rank(close / delay(close, 5) - 1)"
            ... }
            >>> FactorValidator.validate(factor)  # 通过
        """
        # 检查核心字段是否存在
        missing_fields = cls.REQUIRED_FIELDS - set(factor_dict.keys())
        if missing_fields:
            raise ValidationError(
                field=list(missing_fields)[0],
                message=f"缺少必需字段: {sorted(missing_fields)}",
            )

        # 检查核心字段类型
        for field in cls.REQUIRED_FIELDS:
            value = factor_dict[field]
            if not isinstance(value, str):
                raise ValidationError(
                    field=field,
                    message=f"期望类型 str，实际类型 {type(value).__name__}",
                )

            # 检查非空字符串
            if not value.strip():
                raise ValidationError(field=field, message="字段不能为空字符串")

    @classmethod
    def get_required_fields(cls) -> List[str]:
        """获取必需字段列表。

        Returns:
            按字母排序的必需字段列表
        """
        return sorted(cls.REQUIRED_FIELDS)

    @classmethod
    def is_valid(cls, factor_dict: Dict[str, Any]) -> bool:
        """快速校验因子字典是否有效。

        不抛出异常，仅返回布尔结果。

        Args:
            factor_dict: 待校验的因子字典

        Returns:
            是否通过校验
        """
        try:
            cls.validate(factor_dict)
            return True
        except ValidationError:
            return False
