#include <exception>
#include <iostream>
#include <vector>
#include <boost/uuid/uuid_io.hpp>
#include "ble/Bluetooth.h"
#include "apps.h"

namespace trygvis {
namespace apps {

using namespace std;
using namespace trygvis::bluetooth;
using namespace trygvis::apps;

class ble_inspect_device : public app {

public:
    ble_inspect_device() : app("ble-inspect-device") {
    }

    ~ble_inspect_device() = default;

    void add_options(po::options_description_easy_init &options) override {
        options
                ("device", po::value<string>()->required(), "The MAC of the device to inspect");
    }

    void scan_callback(BluetoothDevice &device) {
        cout << "Inspecting device: " << device.getMac().str() << endl;

        auto gatt = device.connectGatt();

        gatt->discoverServices();

        vector < BluetoothGattService * > services = gatt->getServices();
        cout << "Device has " << services.size() << " services" << endl;

        for (auto &s: services) {
            const vector<BluetoothGattCharacteristic *> characteristics = s->getCharacteristics();

            cout << "Service: UUID: " << s->getUuid() <<
                    ", has " << characteristics.size() << " characteristics" << endl;

            for (auto &c: characteristics) {
                cout << "Characteristic: UUID: " << c->getUuid() <<
                        ", properties: " << (int) c->getProperties() << endl;
            }
        }
    }

    int main(app_execution &execution) override {
        string mac_str = execution.vm["device"].as<string>();

        BluetoothSystem bluetoothSystem;

        try {
            Mac mac = Mac::parseMac(mac_str);

            shared_ptr<BluetoothAdapter> adapter = getAdapter(0);

            BluetoothDevice &device = adapter->getDevice(mac);

            scan_callback(device);

            return EXIT_SUCCESS;
        } catch (std::runtime_error ex) {
            cout << "std::runtime_error: " << ex.what() << endl;
            return EXIT_FAILURE;
        } catch (std::exception ex) {
            cout << "std::exception: " << ex.what() << endl;
            return EXIT_FAILURE;
        }
    }
};

}
}