#!/usr/bin/env python3
"""
配置工具模块：边界值验证、向后兼容配置读取、类型转换辅助。
"""

import logging
from typing import Any, Optional, TypeVar, cast, overload

logger = logging.getLogger(__name__)

# 数值类型别名：用于边界校验（int/float 均支持比较运算）
Number = int | float

T = TypeVar("T")


@overload
def clamp_value(
    value: int,
    min_val: int,
    max_val: int,
    field_name: str,
    log_warning: bool = True,
) -> int: ...


@overload
def clamp_value(
    value: float,
    min_val: float,
    max_val: float,
    field_name: str,
    log_warning: bool = True,
) -> float: ...


def clamp_value(
    value: Number,
    min_val: Number,
    max_val: Number,
    field_name: str,
    log_warning: bool = True,
) -> Number:
    """将值限制在 [min_val, max_val] 范围内，超出时记录警告"""
    if value < min_val:
        if log_warning:
            logger.warning(f"{field_name} ({value}) 小于最小值 {min_val}，已调整")
        return min_val
    if value > max_val:
        if log_warning:
            logger.warning(f"{field_name} ({value}) 大于最大值 {max_val}，已调整")
        return max_val
    return value


def clamp_dataclass_field(
    obj: Any,
    field_name: str,
    min_val: Number,
    max_val: Number,
) -> None:
    """在 dataclass __post_init__ 中限制字段值（支持 frozen=True）"""
    current_value = getattr(obj, field_name)
    clamped_value = clamp_value(
        cast(Number, current_value), min_val, max_val, field_name
    )
    if current_value != clamped_value:
        object.__setattr__(obj, field_name, clamped_value)


def get_compat_config(
    config: dict,
    new_key: str,
    old_key: Optional[str] = None,
    default: Any = None,
) -> Any:
    """获取配置值，优先级：new_key > old_key > default"""
    if new_key in config:
        return config[new_key]
    if old_key and old_key in config:
        return config[old_key]
    return default


def get_typed_config(
    config: dict,
    key: str,
    default: T,
    value_type: type[T],
    min_val: Number | None = None,
    max_val: Number | None = None,
    old_key: Optional[str] = None,
) -> T:
    """获取配置值并进行类型转换和边界验证"""
    raw_value = get_compat_config(config, key, old_key, default)

    # 类型转换
    typed_value: T = default
    try:
        if value_type is bool and isinstance(raw_value, str):
            # 特殊处理字符串布尔值
            typed_value = cast(T, raw_value.lower() in ("true", "1", "yes", "on"))
        else:
            typed_value = cast(T, cast(Any, value_type)(raw_value))
    except (ValueError, TypeError):
        logger.warning(
            f"配置 {key} 值 '{raw_value}' 类型转换失败，使用默认值 {default}"
        )
        typed_value = default

    # 边界验证（仅对数值类型）
    if min_val is not None and max_val is not None:
        if isinstance(typed_value, (int, float)):
            typed_value = cast(
                T,
                clamp_value(
                    cast(Number, typed_value),
                    min_val,
                    max_val,
                    key,
                ),
            )

    return typed_value


def validate_enum_value(
    value: str,
    valid_values: tuple,
    field_name: str,
    default: str,
) -> str:
    """验证枚举值是否在有效范围内，无效时返回默认值"""
    if value in valid_values:
        return value
    logger.warning(
        f"{field_name} '{value}' 无效，有效值: {valid_values}，使用默认值 '{default}'"
    )
    return default


def truncate_string(
    value: str | None,
    max_length: int,
    field_name: str,
    default: Optional[str] = None,
    log_warning: bool = True,
) -> str:
    """截断字符串到指定长度，空值时使用默认值"""
    # 处理空值
    if not value or not value.strip():
        if default is not None:
            if log_warning:
                logger.warning(f"{field_name} 为空，使用默认值")
            return default
        return value if value is not None else ""

    # 截断过长的字符串
    if len(value) > max_length:
        if log_warning:
            logger.warning(f"{field_name} 过长 ({len(value)}>{max_length})，已截断")
        return value[:max_length]

    return value
