#include <signal.h>
#include <string.h>
#include <syslog.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <stdbool.h>
#include <alloca.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <pthread.h>

#include <glib.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <bluetooth/l2cap.h>

#include "dy_utils/dy_mqtt.h"
#include "dy_utils/dy_list.h"
#include "dy_utils/dy_common.h"
#include "dy_utils/dy_pp.h"
#include "dy_utils/dy_db.h"
#include "dy_utils/dy_ipc.h"

#include "lib/uuid.h"
#include "gdbus/gdbus.h"

#define DEBUG 1

#define GATT_MGR_IFACE "org.bluez.GattManager1"
#define GATT_SERVICE_IFACE "org.bluez.GattService1"
#define GATT_CHR_IFACE "org.bluez.GattCharacteristic1"
#define GATT_DESCRIPTOR_IFACE "org.bluez.GattDescriptor1"

typedef struct _ble_var_s ble_var_t;
typedef struct _ble_dev_s ble_dev_t;

typedef enum
{
    SCAN_NONE = 0,
    SCAN_SCANNING = 1,
} scan_state;

typedef struct ble_scanner_cfg_s
{
    bool enable;
    scan_state state;
    int scan_fd;
    GIOChannel *io;

    /*
	0x00 Duplicate filtering disabled.
	0x01 Duplicate filtering enabled
	The Filter_Duplicates parameter controls whether the Link Layer should filter
	out duplicate advertising reports (Filtering_Enabled) to the Host, or if the Link
	Layer should generate advertising reports for each packet received
	(Filtering_Disabled). 
	*/
    uint8_t filter_dup;

    /*
	0x00 Passive Scanning. No scanning PDUs shall be sent (default)
	0x01 Active scanning. Scanning PDUs may be sent.
	*/
    uint8_t scan_type;
    /*
	The LE_Scan_Window parameter shall always be set to a value
	smaller or equal to the value set for the LE_Scan_Interval parameter. If they
	are set to the same value scanning should be run continuously
	*/
    /*
	This is defined as the time interval from when the Controller
	started its last LE scan until it begins the subsequent LE scan
	Time Range: 2.5 ms to 10.24 s
	*/
    uint16_t interval;

    /*
	The duration of the LE scan. LE_Scan_Window shall be less
	than or equal to LE_Scan_Interval
	Time Range: 2.5 ms to 10.24 s
	*/
    uint16_t window;
    /*
	0x00 Accept all advertising and scan response PDUs except directed advertising PDUs not addressed to this device (default)
	0x01 Accept only advertising and scan response PDUs from devices where
		the advertiser’s address is in the White List. Directed advertising PDUs
		which are not addressed to this device shall be ignored
	0x02 Accept all advertising and scan response PDUs except directed advertising PDUs where the identity address corresponding to TargetA does
		not address this device.
		Note: Directed advertising PDUs where TargetA is a resolvable private
		address that cannot be resolved are also accepted.
	0x03 Accept all advertising and scan response PDUs except:
		• advertising and scan response PDUs where the advertiser's identity
		address is not in the White List; and
		• directed advertising PDUs where the identity address corresponding
		to TargetA does not address this device.
		Note: Directed advertising PDUs where TargetA is a resolvable private
		address that cannot be resolved are also accepted.
	*/
    uint8_t filter_policy; // do not filter duplicates
                           /*
	Own_Address_Type parameter indicates the type of address being used in the
	scan request packets.
	*/
    uint8_t own_type;

    ble_dev_t *dev;
} ble_scanner_cfg_t;

typedef struct ble_advertising_cfg_s
{
    bool enable;
    /*
	The Advertising_Interval_Min shall be less than or equal to the
	Advertising_Interval_Max. The Advertising_Interval_Min and
	Advertising_Interval_Max should not be the same value to enable the
	Controller to determine the best advertising interval given other activities.
	*/
    uint16_t min_interval;
    uint16_t max_interval;
    /*
	0x00 Connectable and scannable undirected advertising (ADV_IND) (default)
	0x01 Connectable high duty cycle directed advertising (ADV_DIRECT_IND, high duty cycle)
	0x02 Scannable undirected advertising (ADV_SCAN_IND)
	0x03 Non connectable undirected advertising (ADV_NONCONN_IND)
	0x04 Connectable low duty cycle directed advertising (ADV_DIRECT_IND, low duty cycle)
	*/
    uint8_t type;

    /*
	0x00 Public Device Address (default)
	0x01 Random Device Address
	0x02 Controller generates Resolvable Private Address based on the local
		IRK from the resolving list. If the resolving list contains no matching
		entry, use the public address.
	0x03 Controller generates Resolvable Private Address based on the local
		IRK from the resolving list. If the resolving list contains no matching
		entry, use the random address from LE_Set_Random_Address.
	*/
    uint8_t own_addr_type;

    /*
	0 Channel 37 shall be used
	1 Channel 38 shall be used
	2 Channel 39 shall be used
	*/
    uint8_t channel_map;

    /*
	0x00 Process scan and connection requests from all devices (i.e., the White List
		is not in use) (default).
	0x01 Process connection requests from all devices and scan requests only from
		devices that are in the White List.
	0x02 Process scan requests from all devices and connection requests only from
		devices that are in the White List.
	0x03 Process scan and connection requests only from devices in the White List.
	*/
    uint8_t filter_policy;

    uint8_t *data;
    uint8_t size;

    ble_dev_t *dev;
} ble_advertising_cfg_t;

typedef struct ble_slave_dev_s
{
    int fd;
    bdaddr_t addr;
    uint8_t addr_type;
    ble_dev_t *dev;
} ble_slave_dev_t;

typedef struct ble_slave_cfg_s
{
    int dev_cnt;
    ble_slave_dev_t *slave;
} ble_slave_cfg_t;

typedef enum
{
    SCANNER = 0,
    MASTER = 1,
    SLAVE = 2,
    MASTER_SLAVE = 3,
    ADVERTISER = 4
} dev_mode_e;

typedef struct ble_gatt_service_desc_s
{
    char *uuid;
    uint32_t permissions;
} ble_gatt_service_desc_t;

typedef struct ble_gatt_service_char_s
{
    char *uuid;
    uint32_t permissions;
    uint8_t properties;
    uint16_t num_desc;
    ble_gatt_service_desc_t *desc;
} ble_gatt_service_char_t;

typedef struct ble_gatt_service_cfg_s
{
    char *uuid;
    bool primary;
    uint16_t num_handles;
    uint16_t num_char;
    ble_gatt_service_char_t *chars;
} ble_gatt_service_cfg_t;

typedef struct ble_gatt_server_cfg_s
{
    bool enable;
    uint8_t addr_type;
    int fd;
    int service_cnt;
    ble_gatt_service_cfg_t *services;
    GSList *services;
} ble_gatt_server_cfg_t;

typedef struct _ble_dev_s
{
    int dev_id;
    bool enable;
    dev_mode_e mode;

    ble_scanner_cfg_t scan_cfg;
    ble_advertising_cfg_t adv_cfg;
    ble_slave_cfg_t slave_cfg;
    ble_gatt_server_cfg_t server_cfg;

    char dev_name[8];
    struct hci_dev_info *di;
    ble_var_t *var;
} ble_dev_t;

typedef struct _ble_var_s
{
    mqtt_session_t *session; //内部broker的MQTT session，用于进程间通信
    int ble_cnt;
    ble_dev_t *dev;
    DBusConnection *con;
    GDBusClient *client;
} ble_var_t;

static inline int read_n(int fd, char *buf, int len)
{
    int t = 0, w;

    while (len > 0)
    {
        if ((w = read(fd, buf, len)) < 0)
        {
            if (errno == EINTR || errno == EAGAIN)
                continue;
            return -1;
        }
        if (!w)
            return 0;
        len -= w;
        buf += w;
        t += w;
    }
    return t;
}

extern bool start_hci_scan(ble_var_t *var, ble_dev_t *dev);
extern bool start_gatt_services(ble_var_t *var, ble_dev_t *dev);
