#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include "base/bt_errno.h"

#include "hci_core.h"

#include "base/bt_common.h"
#include "utils/byteorder.h"


#include "utils/slist.h"
#include "common/bt_buf.h"
#include "utils/sys_timer.h"
#include "utils/sys_timeout.h"

#include "hci/hci_def.h"

#include "common/gap_def.h"

#include <drivers/hci_driver.h>

#define LOG_MODULE_NAME bt_hci_core_ext
#include "bt_log.h"

#include "conn.h"
#include "l2cap.h"

// int bt_read_remote_version(struct bt_conn *conn)
// {
//     struct bt_hci_cp_read_remote_version_info *cp;
//     simple_buf_t *buf;

//     if (conn->state != BT_CONN_CONNECTED)
//     {
//         return -ENOTCONN;
//     }

//     buf = bt_hci_cmd_create(BT_HCI_OP_READ_REMOTE_VERSION_INFO, sizeof(*cp));
//     if (!buf)
//     {
//         return -ENOBUFS;
//     }

//     cp = simple_buf_add(buf, sizeof(*cp));
//     cp->handle = sys_cpu_to_le16(conn->handle);

//     return bt_hci_cmd_send_sync(BT_HCI_OP_READ_REMOTE_VERSION_INFO, buf, NULL);
// }

/* LE Data Length Change Event is optional so this function just ignore
 * error and stack will continue to use default values.
 */
int bt_le_set_data_len(struct bt_conn *conn, uint16_t tx_octets, uint16_t tx_time)
{
    struct bt_hci_cp_le_set_data_len *cp;
    simple_buf_t *buf;

    buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_DATA_LEN, sizeof(*cp));
    if (!buf)
    {
        return -ENOBUFS;
    }

    cp = simple_buf_add(buf, sizeof(*cp));
    cp->handle = sys_cpu_to_le16(conn->handle);
    cp->tx_octets = sys_cpu_to_le16(tx_octets);
    cp->tx_time = sys_cpu_to_le16(tx_time);

    return bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_DATA_LEN, buf, NULL);
}


int bt_le_set_phy(struct bt_conn *conn, uint8_t all_phys, uint8_t pref_tx_phy, uint8_t pref_rx_phy,
                  uint8_t phy_opts)
{
    struct bt_hci_cp_le_set_phy *cp;
    simple_buf_t *buf;

    buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_PHY, sizeof(*cp));
    if (!buf)
    {
        return -ENOBUFS;
    }

    cp = simple_buf_add(buf, sizeof(*cp));
    cp->handle = sys_cpu_to_le16(conn->handle);
    cp->all_phys = all_phys;
    cp->tx_phys = pref_tx_phy;
    cp->rx_phys = pref_rx_phy;
    cp->phy_opts = phy_opts;

    return bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_PHY, buf, NULL);
}

int bt_le_conn_params_valid(const struct bt_le_conn_param *param)
{
    /* All limits according to BT Core spec 5.0 [Vol 2, Part E, 7.8.12] */

    if (param->interval_min > param->interval_max || param->interval_min < 6 ||
        param->interval_max > 3200)
    {
        return false;
    }

    if (param->latency > 499)
    {
        return false;
    }

    if (param->timeout < 10 || param->timeout > 3200 ||
        ((param->timeout * 4U) <= ((1U + param->latency) * param->interval_max)))
    {
        return false;
    }

    return true;
}

enum bt_security_err bt_security_err_get(uint8_t hci_err)
{
    switch (hci_err)
    {
    case BT_ERR_SUCCESS:
        return BT_SECURITY_ERR_SUCCESS;
    case BT_ERR_AUTH_FAIL:
        return BT_SECURITY_ERR_AUTH_FAIL;
    case BT_ERR_PIN_OR_KEY_MISSING:
        return BT_SECURITY_ERR_PIN_OR_KEY_MISSING;
    case BT_ERR_PAIRING_NOT_SUPPORTED:
        return BT_SECURITY_ERR_PAIR_NOT_SUPPORTED;
    case BT_ERR_PAIRING_NOT_ALLOWED:
        return BT_SECURITY_ERR_PAIR_NOT_ALLOWED;
    case BT_ERR_INVALID_PARAM:
        return BT_SECURITY_ERR_INVALID_PARAM;
    default:
        return BT_SECURITY_ERR_UNSPECIFIED;
    }
}