import pytest
import numpy as np
from privacy_tuner.core.param_utils import is_valid_combo, sample_valid_combo


def test_is_valid_combo_simple():
    space = {
        'mechanism': ['laplace', 'gaussian'],
        'noise_scale': {
            'type': 'float',
            'range': (0.0, 1.0),
            'dependencies': {'mechanism': ['laplace']}
        }
    }
    # 合法组合
    params = {'mechanism': 'laplace', 'noise_scale': 0.5}
    assert is_valid_combo(params, space) == True

    # 非法组合（机制不匹配）
    params = {'mechanism': 'gaussian', 'noise_scale': 0.5}
    assert is_valid_combo(params, space) == False

    # 缺少依赖参数
    params = {'mechanism': 'laplace'}
    assert is_valid_combo(params, space) == True  # 无依赖参数时，检查通过


def test_is_valid_combo_multiple_deps():
    space = {
        'type': ['A', 'B'],
        'param1': {
            'type': 'int',
            'range': (1, 5),
            'dependencies': {'type': ['A']}
        },
        'param2': {
            'type': 'float',
            'range': (0.0, 1.0),
            'dependencies': {'type': ['B']}
        }
    }
    params = {'type': 'A', 'param1': 3}
    assert is_valid_combo(params, space) == True

    params = {'type': 'A', 'param2': 0.5}
    assert is_valid_combo(params, space) == False  # param2 不允许在 type=A 时出现


def test_sample_valid_combo():
    space = {
        'mechanism': ['laplace', 'gaussian', 'copula'],
        'noise_scale': {
            'type': 'float',
            'range': (0.0, 1.0),
            'dependencies': {'mechanism': ['laplace', 'gaussian']}
        },
        'sampling_ratio': {
            'type': 'float',
            'range': (0.5, 2.0),
            'dependencies': {'mechanism': ['copula']}
        }
    }
    np.random.seed(42)
    sample = sample_valid_combo(space)
    assert sample is not None
    assert 'mechanism' in sample
    # 检查合法性
    assert is_valid_combo(sample, space)
    # 检查依赖：如果 mechanism 是 copula，则应有 sampling_ratio，无 noise_scale
    if sample['mechanism'] == 'copula':
        assert 'sampling_ratio' in sample
        assert 'noise_scale' not in sample
    else:
        assert 'noise_scale' in sample
        assert 'sampling_ratio' not in sample