/*******************************************************************************
 * @file    ble_security.c
 * @brief   BLE Security - Peer Manager, LESC, Bonding
 * @author  Charles KWON <charleskwon@medithings.co.kr>
 * @date    2025-01-30
 * @copyright (c) 2025 Medithings Inc. All rights reserved.
 *
 * @details Peer Manager initialization and security event handling.
 ******************************************************************************/

#include "sdk_config.h"
#include "ble_security.h"

#if FEATURE_SECURE_CONNECTION

#include "ble_core.h"
#include "ble_data_tx.h"
#include "power_ctrl.h"
#include "device_config.h"

#include "peer_manager.h"
#include "peer_manager_handler.h"
#include "nrf_ble_lesc.h"
#include "ble_conn_state.h"
#include "app_error.h"
#include "debug_print.h"
#include "battery_saadc.h"
#include "ble_quick_security.h"
#include <string.h>

/*==============================================================================
 * GLOBAL VARIABLES
 *============================================================================*/

bool erase_bonds = false;

/*==============================================================================
 * PRIVATE VARIABLES
 *============================================================================*/

static pm_peer_id_t m_peer_to_be_deleted = PM_PEER_ID_INVALID;
static uint8_t c_addr[6];

/*==============================================================================
 * PEER MANAGER EVENT HANDLER
 *============================================================================*/

static void pm_evt_handler(pm_evt_t const * p_evt)
{
    pm_peer_data_bonding_t peer_bonding_data;
    uint32_t return_code;
    ret_code_t err_code;

    /* Standard Peer Manager handlers */
    pm_handler_on_pm_evt(p_evt);
    pm_handler_disconnect_on_sec_failure(p_evt);
    pm_handler_flash_clean(p_evt);

    /* Security module (automatic mode handling) */
    ble_security_quick_pm_handler(p_evt);

    /* Application-specific event handling */
    switch (p_evt->evt_id)
    {
        case PM_EVT_CONN_SEC_SUCCEEDED:
        {
            pm_conn_sec_status_t conn_sec_status;
            err_code = pm_conn_sec_status_get(p_evt->conn_handle, &conn_sec_status);
            APP_ERROR_CHECK(err_code);

            /* Accept if: MITM protected OR dev mode (no security) */
            if (conn_sec_status.mitm_protected || BLE_DEV_MODE)
            {
                DBG_PRINTF("Link secured. Role: %d, conn_handle: %d, Procedure: %d\r\n",
                          ble_conn_state_role(p_evt->conn_handle),
                          p_evt->conn_handle,
                          p_evt->params.conn_sec_succeeded.procedure);

                /* Start battery monitoring after secure connection */
                ble_connection_st = 1;
                battery_timer_start();
            }
            else
            {
                /* Security insufficient - disconnect (production mode) */
                DBG_PRINTF("Link security FAILED\r\n");
                err_code = pm_peer_id_get(m_conn_handle, &m_peer_to_be_deleted);
                APP_ERROR_CHECK(err_code);
                err_code = sd_ble_gap_disconnect(m_conn_handle,
                                                BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                APP_ERROR_CHECK(err_code);
            }
        }
        break;

        case PM_EVT_CONN_SEC_FAILED:
        {
            DBG_PRINTF("Security failed: peer_id=%d, error=%d\r\n",
                      p_evt->peer_id,
                      p_evt->params.conn_sec_failed.error);

            /* Auto-retry if key missing (supports rebonding) */
            if (p_evt->params.conn_sec_failed.error == PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING)
            {
                err_code = pm_conn_secure(p_evt->conn_handle, true);
                if (err_code != NRF_ERROR_INVALID_STATE)
                {
                    APP_ERROR_CHECK(err_code);
                }
            }
        }
        break;

        case PM_EVT_PEERS_DELETE_SUCCEEDED:
            /* Restart advertising after bond deletion */
            advertising_start(false);
            break;

        case PM_EVT_CONN_SEC_CONFIG_REQ:
        {
            /* Allow repairing for rebonding support */
            pm_conn_sec_config_t conn_sec_config = {
                .allow_repairing = true
            };
            pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config);
        }
        break;

        case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
        {
            /* Store peer address for tracking */
            return_code = pm_peer_data_bonding_load(p_evt->peer_id, &peer_bonding_data);

            if (return_code == NRF_SUCCESS)
            {
                DBG_PRINTF("Peer updated: %02x:%02x:%02x:%02x:%02x:%02x\r\n",
                          peer_bonding_data.peer_ble_id.id_addr_info.addr[5],
                          peer_bonding_data.peer_ble_id.id_addr_info.addr[4],
                          peer_bonding_data.peer_ble_id.id_addr_info.addr[3],
                          peer_bonding_data.peer_ble_id.id_addr_info.addr[2],
                          peer_bonding_data.peer_ble_id.id_addr_info.addr[1],
                          peer_bonding_data.peer_ble_id.id_addr_info.addr[0]);

                memcpy(c_addr,
                      peer_bonding_data.peer_ble_id.id_addr_info.addr,
                      sizeof(c_addr));

                DBG_PRINTF("Stored c_addr[3]: %02x\r\n", c_addr[3]);
                m_reset_status = 10;
            }
            else
            {
                DBG_PRINTF("Failed to load peer data: error=%d\r\n", return_code);
                m_reset_status = 10;
            }
        }
        break;

        default:
            break;
    }
}

/*==============================================================================
 * PUBLIC FUNCTIONS
 *============================================================================*/

void peer_manager_init(void)
{
    ret_code_t err_code;

    /* Security mode auto-configuration */
    ble_security_quick_init(BLE_DEV_MODE);

    /* Register PM event handler */
    err_code = pm_register(pm_evt_handler);
    APP_ERROR_CHECK(err_code);

    DBG_PRINTF("BLE Security initialized (mode=%d)\r\n", BLE_DEV_MODE);
}

void delete_bonds(void)
{
    ret_code_t err_code;

    DBG_PRINTF("Erase bonds!\r\n");

    err_code = pm_peers_delete();
    APP_ERROR_CHECK(err_code);
}

void security_idle_state_handle(void)
{
    ret_code_t err_code;
    err_code = nrf_ble_lesc_request_handler();
    APP_ERROR_CHECK(err_code);
}

#endif /* FEATURE_SECURE_CONNECTION */
