# -*- coding: utf-8 -*-
"""
必需配置缺失检测属性测试

**Validates: Requirements 4.4**

Property 4: 必需配置缺失检测
对于任意必需配置项，当所有配置层级（.env、.env.local、环境变量、CLI）
均未提供该项时，配置加载器应抛出错误，且错误信息中包含该缺失配置项的名称。
"""
import pytest
from hypothesis import given, settings
from hypothesis.strategies import lists, from_regex


def validate_required_config(required_keys: list[str], config: dict) -> None:
    """验证必需配置项是否全部存在且非空。

    Args:
        required_keys: 必需配置项名称列表
        config: 实际配置字典

    Raises:
        ValueError: 当存在缺失或空值的必需配置项时，
                    错误信息包含所有缺失项名称
    """
    missing = [k for k in required_keys if k not in config or not config[k]]
    if missing:
        raise ValueError(f"缺失必需配置项: {', '.join(missing)}")


# 合法配置项名称：大写字母开头，后跟大写字母/数字/下划线
_key_strategy = from_regex(r"[A-Z][A-Z0-9_]{0,19}", fullmatch=True)


@given(
    required_keys=lists(
        _key_strategy,
        min_size=1,
        max_size=5,
        unique=True,
    )
)
@settings(max_examples=100)
def test_missing_required_config_raises_error(required_keys: list[str]):
    """
    Property 4: 空配置字典 -> 抛出 ValueError 且包含缺失项名称

    **Validates: Requirements 4.4**
    """
    empty_config: dict = {}

    with pytest.raises(ValueError, match="缺失必需配置项"):
        validate_required_config(required_keys, empty_config)

    # 额外验证：错误信息包含每个缺失项名称
    try:
        validate_required_config(required_keys, empty_config)
    except ValueError as exc:
        msg = str(exc)
        for key in required_keys:
            assert key in msg, (
                f"错误信息应包含缺失配置项 '{key}'，但实际信息为: {msg}"
            )


@given(
    required_keys=lists(
        _key_strategy,
        min_size=1,
        max_size=5,
        unique=True,
    )
)
@settings(max_examples=100)
def test_empty_value_treated_as_missing(required_keys: list[str]):
    """
    Property 4: 空值视为缺失 -> 抛出 ValueError

    **Validates: Requirements 4.4**
    """
    config_with_empty = {k: "" for k in required_keys}

    with pytest.raises(ValueError, match="缺失必需配置项"):
        validate_required_config(required_keys, config_with_empty)


@given(
    required_keys=lists(
        _key_strategy,
        min_size=1,
        max_size=5,
        unique=True,
    )
)
@settings(max_examples=100)
def test_all_required_present_no_error(required_keys: list[str]):
    """
    Property 4 反向验证：所有必需项均提供非空值时不抛异常

    **Validates: Requirements 4.4**
    """
    config_complete = {k: f"value_for_{k}" for k in required_keys}
    validate_required_config(required_keys, config_complete)
