#!/usr/bin/python3
import ubus
import os
import time

# config info
config = "owrt-1wire-protocol"
config_path = "/etc/config/"

# ubus methods info
test_ubus_objects = [
    {
        'uobj': 'owrt-1wire-dev',
        'umethods': [
            {
                'umethod': 'get_1wire_list',
                'inparams': {
                    "ubus_rpc_session":"0101"
                },
                'outparams': {
                    '1wire_dev': ["__eq__", []]
                }
            },
            {
                'umethod': 'get_1wire_resources',
                'inparams': {
                    "id_1wire": "22.AABBCCDDEEFF",
                    "ubus_rpc_session":"0101"
                },
                'outparams': 'multi',
                'outparams_multi': [
                    {
                        'rd': ["__eq__", []],
                        'wr': ["__eq__", []]
                    },
                    {
                        'xxx': 'Device not found'
                    }
                ]
            },
            {
                'umethod': 'get_value_1wire',
                'inparams': {
                    "id_1wire": "22.AABBCCDDEEFF",
                    "name_val": "temperature",
                    "ubus_rpc_session":"0101"
                },
                'outparams': {
                    'value': ["__eq__", ""],
                    'status': ["__contains__", [str(x) for x in range(-1,1)]]
                }
            },
            {
                'umethod': 'set_value_1wire',
                'inparams': {
                    "id_1wire": "22.AABBCCDDEEFF",
                    "resource": "templow",
                    "value": "11",
                    "ubus_rpc_session":"0101"
                },
                'outparams': {
                    'result': ["__contains__", [str(x) for x in range(-1,1)]]
                }
            },
        ]
    },
]

try:
    ubus.connect()
except:
    print("Can't connect to ubus")


def test_conf_existance():
    ret = False

    try:
        ret = os.path.isfile(f"{config_path}{config}")
    except:
        assert ret

    assert ret


def test_conf_valid():
    ret = False

    try:
        confvalues = ubus.call("uci", "get", {"config": config})
        for confdict in list(confvalues[0]['values'].values()):
            # check globals
            if confdict['.type'] == 'sensor' and confdict['.name'] == 'globals':
                assert confdict['default_memo'] == '1wire'
                assert confdict['bus'] == ['sensor', 'fake', 'i2c']
                assert confdict['default_period'] == '3'
            # check 1wire_prototype_sensor
            if confdict['.type'] == 'sensor' and confdict['.name'] == '1wire_prototype_sensor':
                assert confdict['memo'] == 'description_sensor'
                assert confdict['bus'] == 'sensor'
                assert confdict['period'] == '3'
            # check 1wire_prototype_fake
            if confdict['.type'] == 'sensor' and confdict['.name'] == '1wire_prototype_fake':
                assert confdict['memo'] == '1wire_fake'
                assert confdict['bus'] == 'fake'
                assert confdict['period'] == '3'
            # check 1wire_prototype_i2c
            if confdict['.type'] == 'sensor' and confdict['.name'] == '1wire_prototype_i2c':
                assert confdict['memo'] == '1wire_i2c'
                assert confdict['bus'] == 'i2c'
                assert confdict['i2c_bus'] == 'i2c-0'
                assert confdict['i2c_addr'] == '0'
                assert confdict['max_device'] == '64'
    except:
        assert ret


def test_ubus_methods_existance():
    ret = False

    try:
        test_uobj_list = [x['uobj'] for x in test_ubus_objects]
        test_uobj_list.sort()
        uobj_list = []
        for l in list(ubus.objects().keys()):
            if l in test_uobj_list:
                uobj_list.append(l)
        uobj_list.sort()
        assert test_uobj_list == uobj_list
    except:
        assert ret


def test_ubus_api():
    ret = False

    try:
        test_uobjs = [x for x in test_ubus_objects]
        for uobj in test_uobjs:
            test_uobj_methods = [x for x in uobj['umethods']]
            for method in test_uobj_methods:
                print(method['umethod'])
                res = ubus.call(uobj['uobj'], method['umethod'], method['inparams'])
                if method['outparams'] != 'multi':
                    assert type(method['outparams']) == type(res[0])
                    if isinstance(method['outparams'], dict):
                        for key in method['outparams']:
                            assert key in res[0]
                            if key in res[0]:
                                if method['outparams'][key][0] == '__contains__':
                                    assert getattr(method['outparams'][key][1], method['outparams'][key][0])(res[0][key])
                                elif method['outparams'][key][0] == '__eq__':
                                    eq = getattr(method['outparams'][key][1], method['outparams'][key][0])(res[0][key])
                                    assert not isinstance(eq, type(NotImplemented))
                else:
                    multi_ret = False
                    for outparam in method['outparams_multi']:
                        multi_ret = True
                        if type(outparam) != type(res[0]):
                            multi_ret = False
                            continue
                        if isinstance(outparam, dict):
                            for key in outparam:
                                if key != 'xxx':
                                    if key not in res[0]:
                                        multi_ret = False
                                        continue
                                    if key in res[0]:
                                        if outparam[key][0] == '__contains__':
                                            if not getattr(outparam[key][1],outparam[key][0])(res[0][key]):
                                                multi_ret = False
                                                continue
                                        elif outparam[key][0] == '__eq__':
                                            eq = getattr(outparam[key][1], outparam[key][0])(res[0][key])
                                            if isinstance(eq, type(NotImplemented)):
                                                multi_ret = False
                                                continue
                                else:
                                    multi_ret = False
                                    for res_key in res[0]:
                                        if res[0][res_key] == outparam[key]:
                                            multi_ret = True
                    assert multi_ret
    except:
        assert ret
