"""
    SoftLayer.tests.basic_tests
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Tests shared code

    :license: MIT, see LICENSE for more details.
"""
import datetime
import SoftLayer
from SoftLayer import testing


class TestExceptions(testing.TestCase):

    def test_softlayer_api_error(self):
        e = SoftLayer.SoftLayerAPIError('fault code', 'fault string')
        self.assertEqual(e.faultCode, 'fault code')
        self.assertEqual(e.faultString, 'fault string')
        self.assertEqual(e.reason, 'fault string')
        self.assertEqual(
            repr(e), "<SoftLayerAPIError(fault code): fault string>")
        self.assertEqual(
            str(e), "SoftLayerAPIError(fault code): fault string")

    def test_parse_error(self):
        e = SoftLayer.ParseError('fault code', 'fault string')
        self.assertEqual(e.faultCode, 'fault code')
        self.assertEqual(e.faultString, 'fault string')
        self.assertEqual(e.reason, 'fault string')
        self.assertEqual(
            repr(e), "<ParseError(fault code): fault string>")
        self.assertEqual(
            str(e), "ParseError(fault code): fault string")


class TestUtils(testing.TestCase):

    def test_query_filter(self):
        result = SoftLayer.utils.query_filter('test')
        self.assertEqual({'operation': '_= test'}, result)

        result = SoftLayer.utils.query_filter('~ test')
        self.assertEqual({'operation': '~ test'}, result)

        result = SoftLayer.utils.query_filter('*test')
        self.assertEqual({'operation': '$= test'}, result)

        result = SoftLayer.utils.query_filter('test*')
        self.assertEqual({'operation': '^= test'}, result)

        result = SoftLayer.utils.query_filter('*test*')
        self.assertEqual({'operation': '*= test'}, result)

        result = SoftLayer.utils.query_filter('> 10')
        self.assertEqual({'operation': '> 10'}, result)

        result = SoftLayer.utils.query_filter('>10')
        self.assertEqual({'operation': '> 10'}, result)

        result = SoftLayer.utils.query_filter(10)
        self.assertEqual({'operation': 10}, result)

    def test_query_filter_date(self):
        result = SoftLayer.utils.query_filter_date("2018-01-01", "2018-01-02")
        expected = {
            'operation': 'betweenDate',
            'options': [
                {'name': 'startDate', 'value': ['1/1/2018 0:0:0']},
                {'name': 'endDate', 'value': ['1/2/2018 0:0:0']}
            ]
        }
        self.assertEqual(expected, result)

    def test_timezone(self):
        utc = SoftLayer.utils.UTC()
        time = datetime.datetime(2018, 1, 1, tzinfo=utc)
        self.assertEqual('2018-01-01 00:00:00+00:00', time.__str__())
        self.assertEqual('UTC', time.tzname())
        self.assertEqual(datetime.timedelta(0), time.dst())
        self.assertEqual(datetime.timedelta(0), time.utcoffset())

    def test_dict_merge(self):
        filter1 = {"virtualGuests": {"hostname": {"operation": "etst"}}}
        filter2 = {"virtualGuests": {"id": {"operation": "orderBy", "options": [{"name": "sort", "value": ["DESC"]}]}}}
        result = SoftLayer.utils.dict_merge(filter1, filter2)

        self.assertEqual(result['virtualGuests']['id']['operation'], 'orderBy')
        self.assertNotIn('id', filter1['virtualGuests'])
        self.assertEqual(result['virtualGuests']['hostname']['operation'], 'etst')


class TestNestedDict(testing.TestCase):

    def test_basic(self):
        n = SoftLayer.utils.NestedDict()
        self.assertEqual(n['test'], SoftLayer.utils.NestedDict())

        n['test_set'] = 1
        self.assertEqual(n['test_set'], 1)

        d = {
            'test': {
                'nested': 1
            }}

        n = SoftLayer.utils.NestedDict(d)
        self.assertEqual(d, n)
        self.assertEqual(n['test']['nested'], 1)

        # new default top level elements should return a new NestedDict()
        self.assertEqual(n['not']['nested'], SoftLayer.utils.NestedDict())

        # NestedDict doesn't convert dict children, just the top level dict
        # so you can't assume the same behavior with children
        self.assertRaises(KeyError, lambda: n['test']['not']['nested'])

    def test_to_dict(self):
        n = SoftLayer.utils.NestedDict()
        n['test']['test1']['test2']['test3'] = {}
        d = n.to_dict()

        self.assertEqual({
            'test': {'test1': {'test2': {'test3': {}}}}
        }, d)
        self.assertEqual(dict, type(d))
        self.assertEqual(dict, type(d['test']))
        self.assertEqual(dict, type(d['test']['test1']))
        self.assertEqual(dict, type(d['test']['test1']['test2']))
        self.assertEqual(dict, type(d['test']['test1']['test2']['test3']))


class TestLookup(testing.TestCase):

    def test_lookup(self):
        d = {'test': {'nested': 1}}
        val = SoftLayer.utils.lookup(d, 'test')
        self.assertEqual(val, {'nested': 1})

        val = SoftLayer.utils.lookup(d, 'test', 'nested')
        self.assertEqual(val, 1)

        val = SoftLayer.utils.lookup(d, 'test1')
        self.assertEqual(val, None)

        val = SoftLayer.utils.lookup(d, 'test1', 'nested1')
        self.assertEqual(val, None)


def is_a(string):
    if string == 'a':
        return ['this', 'is', 'a']


def is_b(string):
    if string == 'b':
        return ['this', 'is', 'b']


class IdentifierFixture(SoftLayer.utils.IdentifierMixin):
    resolvers = [is_a, is_b]


class TestIdentifierMixin(testing.TestCase):

    def set_up(self):
        self.fixture = IdentifierFixture()

    def test_integer(self):
        ids = self.fixture.resolve_ids(1234)
        self.assertEqual(ids, [1234])

    def test_a(self):
        ids = self.fixture.resolve_ids('a')
        self.assertEqual(ids, ['this', 'is', 'a'])

    def test_b(self):
        ids = self.fixture.resolve_ids('b')
        self.assertEqual(ids, ['this', 'is', 'b'])

    def test_not_found(self):
        ids = self.fixture.resolve_ids('something')
        self.assertEqual(ids, [])

    def test_globalidentifier(self):
        ids = self.fixture.resolve_ids('9d888bc2-7c9a-4dba-bbd8-6bd688687bae')
        self.assertEqual(ids, ['9d888bc2-7c9a-4dba-bbd8-6bd688687bae'])

    def test_globalidentifier_upper(self):
        ids = self.fixture.resolve_ids('B534EF96-55C4-4891-B51A-63866411B58E')
        self.assertEqual(ids, ['B534EF96-55C4-4891-B51A-63866411B58E'])
