import pytest

import copy
import datetime
from imecilabt_utils.utils import duration_string_to_seconds, strip_null_from_json_dict, datetime_now


def test_now1():
    actual = datetime_now(zulu=True, no_milliseconds=True)
    assert actual.microsecond == 0
    assert actual.isoformat().endswith('+00:00')


def test_now2():
    actual = datetime_now(zulu=True, no_milliseconds=False)
    # Very small chance microsecond happens to be exactly 0, which will make this test fail.
    # Not sure how to solve that...
    assert actual.microsecond != 0
    assert actual.isoformat().endswith('+00:00')


# def test_now3():
#     zulu_tz = datetime.timezone(datetime.timedelta(hours=0), name="UTC")
#
#     actual = datetime_now(zulu=False, no_milliseconds=True)
#     print('local timezone offset = {}'.format(tzlocal()._std_offset))
#     if tzlocal()._std_offset == 0 or tzlocal()._dst_offset == 0:
#         return  # cannot test when local timezone is UTC or near it
#     assert actual.microsecond == 0
#     actual_str = dump_rfc3339(actual, zulu=False, no_milliseconds=False)
#     print('actual_str = {}'.format(actual_str))
#     assert not actual_str.endswith('Z') and not actual_str.endswith('00:00')


def test_duration_string_to_seconds_a():
    assert duration_string_to_seconds('5 mins') == 5 * 60
    assert duration_string_to_seconds('5 hour') == 5 * 60 * 60
    assert duration_string_to_seconds('5 s') == 5
    assert duration_string_to_seconds('5 days') == 5 * 60 * 60 * 24
    assert duration_string_to_seconds('5 week') == 5 * 60 * 60 * 24 * 7


def test_duration_string_to_seconds_b():
    assert duration_string_to_seconds('5m') == 5 * 60
    assert duration_string_to_seconds('5h') == 5 * 60 * 60
    assert duration_string_to_seconds('5secs') == 5
    assert duration_string_to_seconds('5day') == 5 * 60 * 60 * 24
    assert duration_string_to_seconds('5weeks') == 5 * 60 * 60 * 24 * 7


def test_duration_string_to_seconds_c():
    assert duration_string_to_seconds('0.5    minutes') == 30
    assert duration_string_to_seconds('0.25   hours') == 15 * 60
    assert duration_string_to_seconds('0.125  day') == 3 * 60 * 60
    assert duration_string_to_seconds('0.1    weeks') == 6 * 60 * 24 * 7


def test_duration_string_to_seconds_d():
    assert duration_string_to_seconds(None) is None
    assert duration_string_to_seconds('5') is None
    assert duration_string_to_seconds('5x') is None
    assert duration_string_to_seconds('5year') is None
    assert duration_string_to_seconds('5 month') is None


STRIP_NULL_TEST_DICT = {
        'testA1': 'ok',
        'testA2': None,
        'testA3': ['ok'],
        'testA4': {'ok': 'ok'},
        'testA5': [],
        'testA6': {},
        'nested': {
            'testB1': 'ok',
            'testB2': None,
            'testB3': ['ok'],
            'testB4': {'ok': 'ok'},
            'testB5': [],
            'testB6': {},
            'nesteddeep': {
                'testC1': 'ok',
                'testC2': None,
                'testC3': ['ok'],
                'testC4': {'ok': 'ok'},
                'testC5': [],
                'testC6': {}
            }
        }
    }


def test_strip_null_from_json_dict_a():
    dict_in = STRIP_NULL_TEST_DICT
    orig = copy.deepcopy(dict_in)
    expected = {
        'testA1': 'ok',
        'testA3': ['ok'],
        'testA4': {'ok': 'ok'},
        'testA5': [],
        'testA6': {},
        'nested': {
            'testB1': 'ok',
            'testB3': ['ok'],
            'testB4': {'ok': 'ok'},
            'testB5': [],
            'testB6': {},
            'nesteddeep': {
                'testC1': 'ok',
                'testC3': ['ok'],
                'testC4': {'ok': 'ok'},
                'testC5': [],
                'testC6': {},
            }
        }
    }
    actual = strip_null_from_json_dict(dict_in)
    assert orig == dict_in, 'original should not be modified!'
    assert actual == expected


def test_strip_null_from_json_dict_b():
    dict_in = STRIP_NULL_TEST_DICT
    orig = copy.deepcopy(dict_in)
    expected = {
        'testA1': 'ok',
        'testA3': ['ok'],
        'testA4': {'ok': 'ok'},
        'testA6': {},
        'nested': {
            'testB1': 'ok',
            'testB3': ['ok'],
            'testB4': {'ok': 'ok'},
            'testB6': {},
            'nesteddeep': {
                'testC1': 'ok',
                'testC3': ['ok'],
                'testC4': {'ok': 'ok'},
                'testC6': {},
            }
        }
    }
    actual = strip_null_from_json_dict(dict_in, strip_empty_list=True)
    assert orig == dict_in, 'original should not be modified!'
    assert actual == expected


def test_strip_null_from_json_dict_c():
    dict_in = STRIP_NULL_TEST_DICT
    orig = copy.deepcopy(dict_in)
    expected = {
        'testA1': 'ok',
        'testA3': ['ok'],
        'testA4': {'ok': 'ok'},
        'testA5': [],
        'nested': {
            'testB1': 'ok',
            'testB3': ['ok'],
            'testB4': {'ok': 'ok'},
            'testB5': [],
            'nesteddeep': {
                'testC1': 'ok',
                'testC3': ['ok'],
                'testC4': {'ok': 'ok'},
                'testC5': [],
            }
        }
    }
    actual = strip_null_from_json_dict(dict_in, strip_empty_dict=True)
    assert orig == dict_in, 'original should not be modified!'
    assert actual == expected


def test_strip_null_from_json_dict_d():
    dict_in = STRIP_NULL_TEST_DICT
    orig = copy.deepcopy(dict_in)
    expected = {
        'testA1': 'ok',
        'testA3': ['ok'],
        'testA4': {'ok': 'ok'},
        'nested': {
            'testB1': 'ok',
            'testB3': ['ok'],
            'testB4': {'ok': 'ok'},
            'nesteddeep': {
                'testC1': 'ok',
                'testC3': ['ok'],
                'testC4': {'ok': 'ok'},
            }
        }
    }
    actual = strip_null_from_json_dict(dict_in, strip_empty_dict=True, strip_empty_list=True)
    assert orig == dict_in, 'original should not be modified!'
    assert actual == expected


def test_strip_null_from_json_dict_e():
    dict_in = copy.deepcopy(STRIP_NULL_TEST_DICT)
    dict_in['testA7'] = {
        'removeme1': None,
        'removeme2': [],
        'removeme3': {},
        'nestedremoveme': {
            'removeme1': None,
            'removeme2': [],
            'removeme3': {},
        }
    }
    orig = copy.deepcopy(dict_in)
    expected = {
        'testA1': 'ok',
        'testA3': ['ok'],
        'testA4': {'ok': 'ok'},
        'nested': {
            'testB1': 'ok',
            'testB3': ['ok'],
            'testB4': {'ok': 'ok'},
            'nesteddeep': {
                'testC1': 'ok',
                'testC3': ['ok'],
                'testC4': {'ok': 'ok'},
            }
        }
    }
    actual = strip_null_from_json_dict(dict_in, strip_empty_dict=True, strip_empty_list=True)
    assert orig == dict_in, 'original should not be modified!'
    assert actual == expected


def test_strip_null_from_json_dict_f():
    dict_in = copy.deepcopy(STRIP_NULL_TEST_DICT)
    dict_in['nestlist'] = [
        {'a1': 'a1', 'b1': None, 'c1': [], 'd1': {}},
        {'a2': 'a2', 'b2': None, 'c2': [], 'd2': {}},
        {'b3': None},
        {'b4': None, 'c4': [], 'd4': {}},
        {}, [],
    ]
    orig = copy.deepcopy(dict_in)
    expected = {
        'testA1': 'ok',
        'testA3': ['ok'],
        'testA4': {'ok': 'ok'},
        'testA5': [],
        'testA6': {},
        'nested': {
            'testB1': 'ok',
            'testB3': ['ok'],
            'testB4': {'ok': 'ok'},
            'testB5': [],
            'testB6': {},
            'nesteddeep': {
                'testC1': 'ok',
                'testC3': ['ok'],
                'testC4': {'ok': 'ok'},
                'testC5': [],
                'testC6': {},
            }
        },
        'nestlist': [
            {'a1': 'a1', 'b1': None, 'c1': [], 'd1': {}},
            {'a2': 'a2', 'b2': None, 'c2': [], 'd2': {}},
            {'b3': None},
            {'b4': None, 'c4': [], 'd4': {}},
            {}, [],
        ]
    }
    actual = strip_null_from_json_dict(dict_in, process_lists=False)
    assert dict_in == orig, 'original should not be modified!'
    assert actual == expected


def test_strip_null_from_json_dict_g():
    dict_in = copy.deepcopy(STRIP_NULL_TEST_DICT)
    dict_in['nestlist'] = [
        {'a1': 'a1', 'b1': None, 'c1': [], 'd1': {}},
        {'a2': 'a2', 'b2': None, 'c2': [], 'd2': {}},
        {'b3': None},
        {'b4': None, 'c4': [], 'd4': {}},
        {}, [],
    ]
    orig = copy.deepcopy(dict_in)
    expected = {
        'testA1': 'ok',
        'testA3': ['ok'],
        'testA4': {'ok': 'ok'},
        'testA5': [],
        'testA6': {},
        'nested': {
            'testB1': 'ok',
            'testB3': ['ok'],
            'testB4': {'ok': 'ok'},
            'testB5': [],
            'testB6': {},
            'nesteddeep': {
                'testC1': 'ok',
                'testC3': ['ok'],
                'testC4': {'ok': 'ok'},
                'testC5': [],
                'testC6': {},
            }
        },
        'nestlist': [
            {'a1': 'a1', 'c1': [], 'd1': {}},
            {'a2': 'a2', 'c2': [], 'd2': {}},
            {},
            {'c4': [], 'd4': {}},
            {}, [],
        ]
    }
    actual = strip_null_from_json_dict(dict_in, process_lists=True)
    assert dict_in == orig, 'original should not be modified!'
    assert actual == expected


def test_strip_null_from_json_dict_h():
    dict_in = copy.deepcopy(STRIP_NULL_TEST_DICT)
    dict_in['nestlist'] = [
        {'a1': 'a1', 'b1': None, 'c1': [], 'd1': {}},
        {'a2': 'a2', 'b2': None, 'c2': [], 'd2': {}},
        {'b3': None},
        {'b4': None, 'c4': [], 'd4': {}},
        {}, [],
    ]
    orig = copy.deepcopy(dict_in)
    expected = {
        'testA1': 'ok',
        'testA3': ['ok'],
        'testA4': {'ok': 'ok'},
        'nested': {
            'testB1': 'ok',
            'testB3': ['ok'],
            'testB4': {'ok': 'ok'},
            'nesteddeep': {
                'testC1': 'ok',
                'testC3': ['ok'],
                'testC4': {'ok': 'ok'},
            }
        },
        'nestlist': [
            {'a1': 'a1'},
            {'a2': 'a2'},
        ]
    }
    actual = strip_null_from_json_dict(dict_in, strip_empty_dict=True, strip_empty_list=True, process_lists=True)
    assert dict_in == orig, 'original should not be modified!'
    assert actual == expected
