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

#include "common/bt_buf.h"

#include "hci/hci_def.h"

#include "host/hci_core.h"
#include "host/l2cap.h"
#include "host/att.h"
#include "host/gatt.h"

#include "conn.h"

#define LOG_MODULE_NAME conn_ext
#include "bt_log.h"

#if defined(CONFIG_BT_CONN)
extern struct bt_conn_cb *conn_cb;

static int send_conn_le_param_update(struct bt_conn *conn, const struct bt_le_conn_param *param)
{
    LOG_DBG("conn %p features 0x%02x params (%d-%d %d %d)", conn, conn->le.features[0],
            param->interval_min, param->interval_max, param->latency, param->timeout);

    /* Proceed only if connection parameters contains valid values*/
    if (!bt_le_conn_params_valid(param))
    {
        return -EINVAL;
    }

    /* Use LE connection parameter request if both local and remote support
     * it; or if local role is central then use LE connection update.
     */
    if ((BT_FEAT_LE_CONN_PARAM_REQ_PROC(bt_dev.le.features) &&
         BT_FEAT_LE_CONN_PARAM_REQ_PROC(conn->le.features)) ||
        (conn->role == BT_HCI_ROLE_CENTRAL))
    {
        int rc;

        rc = bt_conn_le_conn_update(conn, param);

        /* store those in case of fallback to L2CAP */
        if (rc == 0)
        {
            conn->le.interval_min = param->interval_min;
            conn->le.interval_max = param->interval_max;
            conn->le.pending_latency = param->latency;
            conn->le.pending_timeout = param->timeout;
        }

        return rc;
    }

    /* If remote central does not support LL Connection Parameters Request
     * Procedure
     */
    return bt_l2cap_update_conn_param(conn, param);
}

// int bt_conn_get_remote_info(struct bt_conn *conn, struct bt_conn_remote_info *remote_info)
// {
//     remote_info->type = conn->type;
// #if defined(CONFIG_BT_REMOTE_VERSION)
//     /* The conn->rv values will be just zeroes if the operation failed */
//     remote_info->version = conn->rv.version;
//     remote_info->manufacturer = conn->rv.manufacturer;
//     remote_info->subversion = conn->rv.subversion;
// #else
//     remote_info->version = 0;
//     remote_info->manufacturer = 0;
//     remote_info->subversion = 0;
// #endif

//     switch (conn->type)
//     {
//     case BT_CONN_TYPE_LE:
//         remote_info->le.features = conn->le.features;
//         return 0;
//     default:
//         return -EINVAL;
//     }
// }

// /* Read Transmit Power Level HCI command */
// static int bt_conn_get_tx_power_level(struct bt_conn *conn, uint8_t type, int8_t *tx_power_level)
// {
//     int err;
//     struct bt_hci_rp_read_tx_power_level *rp;
//     simple_buf_t *rsp;
//     struct bt_hci_cp_read_tx_power_level *cp;
//     simple_buf_t *buf;

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

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

//     err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_TX_POWER_LEVEL, buf, &rsp);
//     if (err)
//     {
//         return err;
//     }

//     rp = (void *)rsp->data;
//     *tx_power_level = rp->tx_power_level;
//     simple_buf_free(rsp);

//     return 0;
// }

// int bt_conn_le_get_tx_power_level(struct bt_conn *conn, struct bt_conn_le_tx_power *tx_power_level)
// {
//     int err;

//     if (tx_power_level->phy != 0)
//     {
//         /* Extend the implementation when LE Enhanced Read Transmit
//          * Power Level HCI command is available for use.
//          */
//         return -ENOTSUP;
//     }

//     err = bt_conn_get_tx_power_level(conn, BT_TX_POWER_LEVEL_CURRENT, &tx_power_level->current_level);
//     if (err)
//     {
//         return err;
//     }

//     err = bt_conn_get_tx_power_level(conn, BT_TX_POWER_LEVEL_MAX, &tx_power_level->max_level);
//     return err;
// }

int bt_conn_le_param_update(struct bt_conn *conn, const struct bt_le_conn_param *param)
{
    LOG_DBG("conn %p features 0x%02x params (%d-%d %d %d)", conn, conn->le.features[0],
            param->interval_min, param->interval_max, param->latency, param->timeout);

    /* Check if there's a need to update conn params */
    if (conn->le.interval >= param->interval_min && conn->le.interval <= param->interval_max &&
        conn->le.latency == param->latency && conn->le.timeout == param->timeout)
    {
        return -EALREADY;
    }

    return send_conn_le_param_update(conn, param);
}

int bt_conn_le_data_len_update(struct bt_conn *conn, const struct bt_conn_le_data_len_param *param)
{
    if (conn->le.data_len.tx_max_len == param->tx_max_len &&
        conn->le.data_len.tx_max_time == param->tx_max_time)
    {
        return -EALREADY;
    }

    return bt_le_set_data_len(conn, param->tx_max_len, param->tx_max_time);
}

int bt_conn_le_phy_update(struct bt_conn *conn, const struct bt_conn_le_phy_param *param)
{
    uint8_t phy_opts, all_phys;

    if ((param->options & BT_CONN_LE_PHY_OPT_CODED_S2) &&
        (param->options & BT_CONN_LE_PHY_OPT_CODED_S8))
    {
        phy_opts = BT_HCI_LE_PHY_CODED_ANY;
    }
    else if (param->options & BT_CONN_LE_PHY_OPT_CODED_S2)
    {
        phy_opts = BT_HCI_LE_PHY_CODED_S2;
    }
    else if (param->options & BT_CONN_LE_PHY_OPT_CODED_S8)
    {
        phy_opts = BT_HCI_LE_PHY_CODED_S8;
    }
    else
    {
        phy_opts = BT_HCI_LE_PHY_CODED_ANY;
    }

    all_phys = 0U;
    if (param->pref_tx_phy == BT_GAP_LE_PHY_NONE)
    {
        all_phys |= BT_HCI_LE_PHY_TX_ANY;
    }

    if (param->pref_rx_phy == BT_GAP_LE_PHY_NONE)
    {
        all_phys |= BT_HCI_LE_PHY_RX_ANY;
    }

    return bt_le_set_phy(conn, all_phys, param->pref_tx_phy, param->pref_rx_phy, phy_opts);
}

int bt_conn_le_conn_update(struct bt_conn *conn, const struct bt_le_conn_param *param)
{
    struct hci_cp_le_conn_update *conn_update;
    simple_buf_t *buf;

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

    conn_update = simple_buf_add(buf, sizeof(*conn_update));
    (void)memset(conn_update, 0, sizeof(*conn_update));
    conn_update->handle = sys_cpu_to_le16(conn->handle);
    conn_update->conn_interval_min = sys_cpu_to_le16(param->interval_min);
    conn_update->conn_interval_max = sys_cpu_to_le16(param->interval_max);
    conn_update->conn_latency = sys_cpu_to_le16(param->latency);
    conn_update->supervision_timeout = sys_cpu_to_le16(param->timeout);

    return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CONN_UPDATE, buf, NULL);
}

#ifdef OMW_EN_DEEP_SLEEP
struct bt_conn * acl_conns = (struct bt_conn *)0x200008d8;
uint8_t bt_conn_can_sleep_check()
{
    int i;

    if (!bt_att_can_sleep()) return 0;

    for (i = 0; i < CONFIG_BT_MAX_CONN; i++)
    {
        struct bt_conn *conn = &acl_conns[i];

        if (conn->tx_acl_buf || (!sys_slist_is_empty(&conn->tx_queue)))
        {
            return 0;
        }
    }

    return 1;
}
#endif

// struct bt_conn_auth_info_cb *bt_auth_info;
// const struct bt_conn_auth_cb *bt_auth;
// int bt_conn_auth_cb_register(const struct bt_conn_auth_cb *cb)
// {
//     if (!cb)
//     {
//         bt_auth = NULL;
//         return 0;
//     }

//     if (bt_auth)
//     {
//         return -EALREADY;
//     }

//     /* The cancel callback must always be provided if the app provides
//      * interactive callbacks.
//      */
//     if (!cb->cancel && (cb->passkey_display || cb->passkey_entry || cb->passkey_confirm || cb->pairing_confirm))
//     {
//         return -EINVAL;
//     }

//     bt_auth = cb;
//     return 0;
// }
#if defined(CONFIG_BT_SMP)
void bt_conn_security_changed(struct bt_conn *conn, uint8_t hci_err, enum bt_security_err err)
{
    struct bt_conn_cb *cb = conn_cb;

    conn->required_sec_level = conn->sec_level;

    bt_l2cap_security_changed(conn, hci_err);

    if (cb && cb->security_changed)
    {
        cb->security_changed(conn, conn->sec_level, err);
    }
}


bt_security_t bt_conn_get_security(const struct bt_conn *conn)
{
    return conn->sec_level;
}

#endif
#endif