"""
数据验证器
数据清洗验证管道
"""
import re
from dataclasses import dataclass, field
from typing import Optional, List, Dict, Any, Callable, Union
from loguru import logger


@dataclass
class ValidationRule:
    """验证规则"""
    name: str
    validate: Callable[[Any, Optional[Dict]], bool]
    message: str = "验证失败"
    is_warning: bool = False


@dataclass
class FieldValidation:
    """字段验证配置"""
    field: str
    rules: List[ValidationRule] = field(default_factory=list)


@dataclass
class ValidationIssue:
    """验证问题"""
    field: str
    rule: str
    message: str


@dataclass
class ValidationResult:
    """验证结果"""
    is_valid: bool
    errors: List[ValidationIssue] = field(default_factory=list)
    warnings: List[ValidationIssue] = field(default_factory=list)


@dataclass
class DataValidatorConfig:
    """数据验证器配置"""
    fields: List[FieldValidation] = field(default_factory=list)
    global_rules: List[ValidationRule] = field(default_factory=list)
    stop_on_first_error: bool = False


class BuiltInRules:
    """内置验证规则"""

    @staticmethod
    def required() -> ValidationRule:
        """必填"""
        return ValidationRule(
            name="required",
            validate=lambda value, _: value is not None and value != "",
            message="字段不能为空",
        )

    @staticmethod
    def email() -> ValidationRule:
        """邮箱格式"""
        return ValidationRule(
            name="email",
            validate=lambda value, _: isinstance(value, str) and bool(re.match(r'^[^\s@]+@[^\s@]+\.[^\s@]+$', value)),
            message="邮箱格式不正确",
        )

    @staticmethod
    def url() -> ValidationRule:
        """URL格式"""
        def validate_url(value, _):
            if not isinstance(value, str):
                return False
            try:
                from urllib.parse import urlparse
                result = urlparse(value)
                return bool(result.scheme and result.netloc)
            except Exception:
                return False

        return ValidationRule(
            name="url",
            validate=validate_url,
            message="URL格式不正确",
        )

    @staticmethod
    def number() -> ValidationRule:
        """数字"""
        return ValidationRule(
            name="number",
            validate=lambda value, _: isinstance(value, (int, float)) and not isinstance(value, bool),
            message="必须是数字",
        )

    @staticmethod
    def integer() -> ValidationRule:
        """整数"""
        return ValidationRule(
            name="integer",
            validate=lambda value, _: isinstance(value, int) and not isinstance(value, bool),
            message="必须是整数",
        )

    @staticmethod
    def positive_number() -> ValidationRule:
        """正数"""
        return ValidationRule(
            name="positive_number",
            validate=lambda value, _: isinstance(value, (int, float)) and value > 0,
            message="必须是正数",
        )

    @staticmethod
    def phone() -> ValidationRule:
        """手机号（中国）"""
        return ValidationRule(
            name="phone",
            validate=lambda value, _: isinstance(value, str) and bool(re.match(r'^1[3-9]\d{9}$', value)),
            message="手机号格式不正确",
        )

    @staticmethod
    def date() -> ValidationRule:
        """日期"""
        def validate_date(value, _):
            if isinstance(value, type(None)):
                return False
            from datetime import datetime
            if isinstance(value, datetime):
                return True
            if isinstance(value, str):
                try:
                    datetime.fromisoformat(value.replace('Z', '+00:00'))
                    return True
                except ValueError:
                    try:
                        datetime.strptime(value, '%Y-%m-%d')
                        return True
                    except ValueError:
                        return False
            return False

        return ValidationRule(
            name="date",
            validate=validate_date,
            message="日期格式不正确",
        )

    @staticmethod
    def min_length(min_len: int) -> ValidationRule:
        """最小长度"""
        return ValidationRule(
            name=f"min_length:{min_len}",
            validate=lambda value, _: len(value) >= min_len if hasattr(value, '__len__') else False,
            message=f"长度不能少于 {min_len}",
        )

    @staticmethod
    def max_length(max_len: int) -> ValidationRule:
        """最大长度"""
        return ValidationRule(
            name=f"max_length:{max_len}",
            validate=lambda value, _: len(value) <= max_len if hasattr(value, '__len__') else False,
            message=f"长度不能超过 {max_len}",
        )

    @staticmethod
    def min_value(min_val: Union[int, float]) -> ValidationRule:
        """最小值"""
        return ValidationRule(
            name=f"min_value:{min_val}",
            validate=lambda value, _: isinstance(value, (int, float)) and value >= min_val,
            message=f"不能小于 {min_val}",
        )

    @staticmethod
    def max_value(max_val: Union[int, float]) -> ValidationRule:
        """最大值"""
        return ValidationRule(
            name=f"max_value:{max_val}",
            validate=lambda value, _: isinstance(value, (int, float)) and value <= max_val,
            message=f"不能大于 {max_val}",
        )

    @staticmethod
    def pattern(regex: str) -> ValidationRule:
        """正则匹配"""
        compiled = re.compile(regex)
        return ValidationRule(
            name=f"pattern:{regex}",
            validate=lambda value, _: isinstance(value, str) and bool(compiled.match(value)),
            message="格式不匹配",
        )

    @staticmethod
    def in_list(choices: List[Any]) -> ValidationRule:
        """在列表中"""
        return ValidationRule(
            name=f"in_list:{choices}",
            validate=lambda value, _: value in choices,
            message=f"值必须在 {choices} 中",
        )


class DataValidator:
    """
    数据验证器
    提供数据验证和清洗功能
    """

    def __init__(self, config: Optional[DataValidatorConfig] = None):
        self.config = config or DataValidatorConfig()
        self._custom_rules: Dict[str, ValidationRule] = {}

    def add_rule(self, name: str, rule: ValidationRule) -> None:
        """添加自定义规则"""
        self._custom_rules[name] = rule

    def validate(self, data: Dict[str, Any]) -> ValidationResult:
        """
        验证单条数据

        Args:
            data: 要验证的数据

        Returns:
            ValidationResult: 验证结果
        """
        errors: List[ValidationIssue] = []
        warnings: List[ValidationIssue] = []

        for field_validation in self.config.fields:
            field_value = data.get(field_validation.field)

            for rule in field_validation.rules:
                try:
                    is_valid = rule.validate(field_value, data)

                    if not is_valid:
                        issue = ValidationIssue(
                            field=field_validation.field,
                            rule=rule.name,
                            message=rule.message,
                        )

                        if rule.is_warning:
                            warnings.append(issue)
                        else:
                            errors.append(issue)

                            if self.config.stop_on_first_error:
                                return ValidationResult(
                                    is_valid=False,
                                    errors=errors,
                                    warnings=warnings,
                                )
                except Exception as e:
                    errors.append(ValidationIssue(
                        field=field_validation.field,
                        rule=rule.name,
                        message=f"验证异常: {str(e)}",
                    ))

        # 执行全局规则
        for rule in self.config.global_rules:
            try:
                is_valid = rule.validate(data)

                if not is_valid:
                    issue = ValidationIssue(
                        field="_global",
                        rule=rule.name,
                        message=rule.message,
                    )

                    if rule.is_warning:
                        warnings.append(issue)
                    else:
                        errors.append(issue)
            except Exception as e:
                errors.append(ValidationIssue(
                    field="_global",
                    rule=rule.name,
                    message=f"验证异常: {str(e)}",
                ))

        return ValidationResult(
            is_valid=len(errors) == 0,
            errors=errors,
            warnings=warnings,
        )

    def validate_batch(
        self,
        data_list: List[Dict[str, Any]],
    ) -> Dict[str, Any]:
        """
        批量验证

        Args:
            data_list: 数据列表

        Returns:
            dict: 包含 valid 和 invalid 列表
        """
        valid: List[Dict[str, Any]] = []
        invalid: List[Dict[str, Any]] = []

        for data in data_list:
            result = self.validate(data)

            if result.is_valid:
                valid.append(data)
            else:
                invalid.append({
                    "data": data,
                    "result": result,
                })

        return {"valid": valid, "invalid": invalid}

    def clean(self, data: Dict[str, Any]) -> Dict[str, Any]:
        """
        数据清洗

        Args:
            data: 原始数据

        Returns:
            dict: 清洗后的数据
        """
        cleaned: Dict[str, Any] = {}

        for key, value in data.items():
            # 移除空值
            if value is None:
                continue

            # 字符串处理
            if isinstance(value, str):
                trimmed = value.strip()
                if trimmed == "":
                    continue
                cleaned[key] = trimmed
            else:
                cleaned[key] = value

        return cleaned

    def transform(
        self,
        data: Dict[str, Any],
        schema: Dict[str, str],
    ) -> Dict[str, Any]:
        """
        类型转换

        Args:
            data: 原始数据
            schema: 类型映射 {"field": "type"}

        Returns:
            dict: 转换后的数据
        """
        from datetime import datetime
        result: Dict[str, Any] = {}

        for key, type_name in schema.items():
            value = data.get(key)

            if value is None:
                result[key] = None
                continue

            try:
                if type_name == "number":
                    result[key] = float(value) if not isinstance(value, (int, float)) else value
                elif type_name == "integer":
                    result[key] = int(float(value)) if not isinstance(value, int) else value
                elif type_name == "boolean":
                    result[key] = bool(value)
                elif type_name == "string":
                    result[key] = str(value)
                elif type_name == "date":
                    if isinstance(value, datetime):
                        result[key] = value
                    else:
                        result[key] = datetime.fromisoformat(str(value).replace('Z', '+00:00'))
                else:
                    result[key] = value
            except Exception:
                result[key] = None

        return result

    def get_rule(self, name: str) -> Optional[ValidationRule]:
        """获取规则"""
        return self._custom_rules.get(name)


def create_data_validator(config: Optional[DataValidatorConfig] = None) -> DataValidator:
    """创建数据验证器实例"""
    return DataValidator(config)
