"""
Tests of non-parametric method regressogram functionality.

Every method to choose optimal width of buckets is tested on a set
of provided examples and the computation results are compared with
the expected values. This ensures that the methods works correctly
always.

The postprocessby CLI is tested in test_cli module.
"""
from perun.postprocess.regressogram.run import postprocess
from perun.testing.utils import profile_filter, compare_results, generate_models_by_uid


def test_regressogram_method(postprocess_profiles):
    """
    Test the regressogram method with user choice of buckets width.

    Expects to pass all assertions.
    """
    # Get the profile with testing data
    test_model = profile_filter(postprocess_profiles, 'exp_model')
    assert test_model is not None

    for current_method in _EXPECTED_RESULTS.keys():
        # Perform the non-parametric analysis using by regressogram
        code, _, profile = postprocess(
            test_model, of_key='amount', statistic_function='mean',
            bucket_number=10 if current_method == 'user' else None,
            bucket_method=current_method if current_method != 'user' else None,
            per_key='structure-unit-size'
        )
        # Expected successful analysis by non-parametric postprocessor
        assert code.value == 0
        # Obtaining generator of models from profile in the UID order
        models = generate_models_by_uid(
            profile, 'regressogram', ['exp::test1', 'exp::test2', 'exp::test3'], key='model'
        )

        # Test the expected result with each obtained model
        for model, exp_result, interval_result in zip(
                models, _EXPECTED_RESULTS[current_method], _COMMON_INTERVAL
        ):
            # Concatenate expected results with interval results to one dict
            exp_result.update(interval_result)
            # Comparison each significant value
            for key in exp_result.keys():
                # Comparison of bucket_stats array length
                if key == 'bucket_stats':
                    assert len(model[0][key]) == exp_result[key]
                # Double comparison of individual values (r_square, x_start, x_end)
                else:
                    compare_results(model[0][key], exp_result[key], eps=0.00001)
        # Remove generated models for next run of iteration
        profile['profile']['models'].clear()


# Common expected interval edges
_COMMON_INTERVAL = [
    # uid: exp::test1
    {'x_start': 0.0, 'x_end': 110.0, 'y_start': 0.2},
    # uid: exp::test2
    {'x_start': 17.0, 'x_end': 103.0, 'y_start': 18.0},
    # uid: exp::test3
    {'x_start': 0.0, 'x_end': 8.0, 'y_start': 1.0}
]

# Expected Results
_EXPECTED_RESULTS = {
    'user': [
        # uid: exp::test1
        {'r_square': 0.98007, 'bucket_stats': 10},
        # uid: exp::test2
        {'r_square': 0.97567, 'bucket_stats': 10},
        # uid: exp::test3
        {'r_square': 1.0, 'bucket_stats': 10},
    ],
    'auto': [
        # uid: exp::test1
        {'r_square': 0.99601, 'bucket_stats': 22},
        # uid: exp::test2
        {'r_square': 0.99428, 'bucket_stats': 19},
        # uid: exp::test3
        {'r_square': 0.0, 'bucket_stats': 1},
    ],
    'doane': [
        # uid: exp::test1
        {'r_square': 0.99601, 'bucket_stats': 20},
        # uid: exp::test2
        {'r_square': 0.99428, 'bucket_stats': 16},
        # uid: exp::test3
        {'r_square': 0.0, 'bucket_stats': 1},
    ],
    'fd': [
        # uid: exp::test1
        {'r_square': 1.0, 'bucket_stats': 50},
        # uid: exp::test2
        {'r_square': 1.0, 'bucket_stats': 36},
        # uid: exp::test3
        {'r_square': 0.66732, 'bucket_stats': 3},
    ],
    'rice': [
        # uid: exp::test1
        {'r_square': 0.99601, 'bucket_stats': 22},
        # uid: exp::test2
        {'r_square': 0.99428, 'bucket_stats': 19},
        # uid: exp::test3
        {'r_square': 0.0, 'bucket_stats': 1},
    ],
    'scott': [
        # uid: exp::test1
        {'r_square': 1.0, 'bucket_stats': 51},
        # uid: exp::test2
        {'r_square': 1.0, 'bucket_stats': 44},
        # uid: exp::test3
        {'r_square': 0.67017, 'bucket_stats': 4},
    ],
    'sqrt': [
        # uid: exp::test1
        {'r_square': 1.0, 'bucket_stats': 29},
        # uid: exp::test2
        {'r_square': 1.0, 'bucket_stats': 25},
        # uid: exp::test3
        {'r_square': 0.34687, 'bucket_stats': 2},
    ],
    'sturges': [
        # uid: exp::test1
        {'r_square': 0.99601, 'bucket_stats': 22},
        # uid: exp::test2
        {'r_square': 0.99428, 'bucket_stats': 19},
        # uid: exp::test3
        {'r_square': 0.0, 'bucket_stats': 1},
    ]
}
