import pytest
import pandas

from pvlib.tests import conftest
from pvlib.tests.conftest import fail_on_pvlib_version

from pvlib._deprecation import pvlibDeprecationWarning, deprecated

@pytest.mark.xfail(strict=True,
                   reason='fail_on_pvlib_version should cause test to fail')
@fail_on_pvlib_version('0.0')
def test_fail_on_pvlib_version():
    pass


@fail_on_pvlib_version('100000.0')
def test_fail_on_pvlib_version_pass():
    pass


@pytest.mark.xfail(strict=True, reason='ensure that the test is called')
@fail_on_pvlib_version('100000.0')
def test_fail_on_pvlib_version_fail_in_test():
    raise Exception


# set up to test using fixtures with function decorated with
# conftest.fail_on_pvlib_version
@pytest.fixture()
def some_data():
    return "some data"


def alt_func(*args):
    return args


deprec_func = deprecated('350.8', alternative='alt_func',
                         name='deprec_func', removal='350.9')(alt_func)


@fail_on_pvlib_version('350.9')
def test_use_fixture_with_decorator(some_data):
    # test that the correct data is returned by the some_data fixture
    assert some_data == "some data"
    with pytest.warns(pvlibDeprecationWarning):  # test for deprecation warning
        deprec_func(some_data)


@pytest.mark.parametrize('function_name', ['assert_index_equal',
                                           'assert_series_equal',
                                           'assert_frame_equal'])
@pytest.mark.parametrize('pd_version', ['1.0.0', '1.1.0'])
@pytest.mark.parametrize('check_less_precise', [True, False])
def test__check_pandas_assert_kwargs(mocker, monkeypatch,
                                     function_name, pd_version,
                                     check_less_precise):
    # test that conftest._check_pandas_assert_kwargs returns appropriate
    # kwargs for the assert_x_equal functions

    # patch the pandas assert; not interested in actually calling them:
    def patched_assert(*args, **kwargs):
        pass

    monkeypatch.setattr(pandas.testing, function_name, patched_assert)
    # then attach a spy to it so we can see what args it is called with:
    mocked_function = mocker.spy(pandas.testing, function_name)
    # patch pd.__version__ to exercise the two branches in
    # conftest._check_pandas_assert_kwargs
    monkeypatch.setattr(pandas, '__version__', pd_version)

    # finally, run the function and check what args got passed to pandas:
    assert_function = getattr(conftest, function_name)
    args = [None, None]
    assert_function(*args, check_less_precise=check_less_precise)
    if pd_version == '1.1.0':
        tol = 1e-3 if check_less_precise else 1e-5
        expected_kwargs = {'atol': tol, 'rtol': tol}
    else:
        expected_kwargs = {'check_less_precise': check_less_precise}

    mocked_function.assert_called_with(*args, **expected_kwargs)
