import bleak
import inspect
import traceback
import pprint


async def f1():
    devices = await bleak.BleakScanner.discover()
    return devices

async def f2(device, timeout=None):
    if timeout is None:
        timeout = 1.0

    assert isinstance(timeout, float) and timeout >= 1e-8

    p = await bleak.BleakClient(
        device,
        timeout=timeout,
    ).__aenter__()
    return p

async def f3(client):
    t1 = [
        dict(
            service=o.__dict__,
            characteristics=[
                o2.__dict__
                for o2 in o.characteristics
            ]
        )
        for o in client.services
    ]
    return t1

async def f5(
    name_check=None,
):
    t2 = []

    attempt = 0

    while True:
        t1 = await f1()
        pprint.pprint([o.__dict__ for o in t1])

        if not name_check is None:
            assert inspect.isfunction(name_check)

            t5 = {
                i : o.details[0].name()
                for i, o in enumerate(t1)
            }

            t2.extend(
                [
                    t1[k]
                    for k, v in t5.items()
                    if isinstance(v, str) and name_check(v)
                ]
            )
        else:
            t2.extend(t1)

        if len(t2) > 0:
            break

        attempt += 1
        print('\rattempt #%d' % attempt, end='')

    return t2

async def f4(
    timeout=None,
    characteristics=None,
    operations=None,
    name_check=None,
):
    if isinstance(name_check, str):
        assert name_check in [
            'watch fit',
        ]
        name_check2 = lambda current_name: name_check.lower() in current_name.lower()
    else:
        name_check2 = name_check

    assert not name_check2 is None

    if characteristics is None:
        characteristics = [
            '0000ffd1-0000-1000-8000-00805f9b34fb',
        ]

    t2 = await f5(
        name_check=name_check2,
    )

    if len(t2) == 0:
        print('not found')
        return

    t3 = None
    try:
        t3 = await f2(t2[0], timeout=timeout)
        t4 = await f3(t3)
        pprint.pprint(t4)

        if not operations is None and inspect.isfunction(operations):
            await operations(
                client=t3,
                t4=t4,
            )
        else:
            t6 = {}
            for o in characteristics:
                try:
                    t7 = await t3.read_gatt_char(o)
                except Exception as exception:
                    print(traceback.format_exc())
                    t7 = None
                t6[o] = t7
            pprint.pprint(t6)
    finally:
        if not t3 is None:
            await t3.disconnect()