/*******************************************************************************
 * @file    power_ctrl.c
 * @brief   Power Management and Control Functions
 * @author  Charles KWON <charleskwon@medithings.co.kr>
 * @date    2025-01-30
 * @copyright (c) 2025 Medithings Inc. All rights reserved.
 *
 * @details Power on/off control, sleep mode, button state machine.
 ******************************************************************************/

#include "sdk_config.h"
#include "power_ctrl.h"
#include "ble_core.h"
#include "nrf_gpio.h"
#include "nrf_delay.h"
#include "app_timer.h"
#include "app_error.h"
#include "bsp.h"
#include "bsp_btn_ble.h"
#include "ble_advertising.h"
#include "debug_print.h"
#include "main.h"
#include "main_timer.h"
#include "battery_saadc.h"
#include "power_control.h"
#include "measurements.h"
#include "cat_interface.h"
#include <cmd_parse.h>
#include "app_raw_main.h"
#include "ada2200_spi.h"
#include "mcp4725_i2c.h"
#include "storage/dr_mem.h"
#include "fstorage.h"

/*==============================================================================
 * EXTERNAL DECLARATIONS
 *============================================================================*/

extern uint16_t m_conn_handle;
extern bool bond_data_delete;
extern bool erase_bonds;
extern volatile bool ble_connection_st;

/* Functions from ble_core module - declared in ble_core.h */

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

volatile bool processing = false;
volatile bool power_state = false;
bool power_off_duble_prohibit = false;
bool device_status = false;
bool device_reset = true;
uint16_t cnt_s = 0;
uint8_t m_reset_status = 0;

bool go_device_power_off = false;
bool go_sleep_mode_enter = false;
bool go_NVIC_SystemReset = false;

/*==============================================================================
 * TIMER INSTANCES
 *============================================================================*/

APP_TIMER_DEF(m_power_on_delay_timer_id);
APP_TIMER_DEF(m_power_off_delay_timer_id);
APP_TIMER_DEF(m_PM_timer_id);

/*==============================================================================
 * TIMER INITIALIZATION
 *============================================================================*/

void power_ctrl_timers_init(void)
{
    APP_ERROR_CHECK(app_timer_create(&m_power_on_delay_timer_id,
                                     APP_TIMER_MODE_SINGLE_SHOT,
                                     power_button_handler));
    APP_ERROR_CHECK(app_timer_create(&m_power_off_delay_timer_id,
                                     APP_TIMER_MODE_SINGLE_SHOT,
                                     power_off_timeout_handler));
    APP_ERROR_CHECK(app_timer_create(&m_PM_timer_id,
                                     APP_TIMER_MODE_SINGLE_SHOT,
                                     pm_timeout_handler));
}

void power_ctrl_timers_start(void)
{
    ret_code_t err_code;
    err_code = app_timer_start(m_power_on_delay_timer_id,
                               APP_TIMER_TICKS(POWER_ON_DELAY), NULL);
    APP_ERROR_CHECK(err_code);
}

/*==============================================================================
 * POWER CONTROL FUNCTIONS
 *============================================================================*/

void power_control_set(on_off_cont_t device_power_st)
{
    if (device_power_st == OFF) {
        nrf_gpio_pin_clear(POWER_HOLD);
        DBG_PRINTF("Main Power OFF\r\n");
    } else if (device_power_st == ON) {
        nrf_gpio_pin_set(POWER_HOLD);
        DBG_PRINTF("Main Power ON\r\n");
    }
}

void device_power_off(void)
{
    uint32_t err_code = bsp_indication_set(BSP_INDICATE_USER_STATE_ON);
    APP_ERROR_CHECK(err_code);
    APP_ERROR_CHECK(app_timer_start(m_power_off_delay_timer_id,
                                    APP_TIMER_TICKS(POWER_OFF_DELAY), NULL));
}

void sleep_mode_enter(void)
{
    uint32_t err_code = bsp_indication_set(BSP_INDICATE_USER_STATE_ON);
    APP_ERROR_CHECK(err_code);
    DBG_PRINTF("go Sleep!\r\n");

    APP_ERROR_CHECK(app_timer_start(m_power_off_delay_timer_id,
                                    APP_TIMER_TICKS(POWER_OFF_DELAY), NULL));
}

/*==============================================================================
 * TIMER CALLBACKS
 *============================================================================*/

void power_off_timeout_handler(void * p_context)
{
    UNUSED_PARAMETER(p_context);
    APP_ERROR_CHECK(app_timer_stop(m_power_off_delay_timer_id));
    DBG_PRINTF("Off stop\r\n");

    uint32_t err_code = bsp_indication_set(BSP_INDICATE_USER_STATE_OFF);
    APP_ERROR_CHECK(err_code);
    power_control_set(OFF);
}

void pm_timeout_handler(void * p_context)
{
    UNUSED_PARAMETER(p_context);
    APP_ERROR_CHECK(app_timer_stop(m_PM_timer_id));

    if (m_reset_status == 5) {
        DBG_PRINTF("kill\r\n");
        disconnect(m_conn_handle, NULL);
    }
}

/*==============================================================================
 * POWER BUTTON STATE MACHINE
 *============================================================================*/

void power_button_handler(void * p_context)
{
    UNUSED_PARAMETER(p_context);
    APP_ERROR_CHECK(app_timer_stop(m_power_on_delay_timer_id));

    if (nrf_gpio_pin_read(POWER_BUTTON)) {
        /* Button released - determine action based on press duration */
        if ((cnt_s < 150) && (m_reset_status != 2)) {
            /* Short press - power off */
            uint32_t err_code = bsp_indication_set(BSP_INDICATE_USER_STATE_OFF);
            (void)err_code;
            power_control_set(OFF);
            cnt_s = 0;
        }
        else if (cnt_s > 1000) {
            /* Very long press - factory reset */
            power_control_set(ON);
            nrf_delay_ms(100);
            bond_data_delete = true;
            /* Factory reset: save defaults to FDS */
            {
                uint8_t bd = (uint8_t)bond_data_delete;
                dr_memWrite("bond_delete", &bd, 1);

                const char pass_init[6] = "123456";
                dr_memWrite("passkey", (uint8_t *)pass_init, 6);
            }
            nrf_delay_ms(1000);

            go_device_power_off = true;
            main_timer_start();
        }
        else if (cnt_s > 150 || (m_reset_status == 2)) {
            /* Long press - normal startup */
            device_reset = false;
            DBG_PRINTF("\r\n\r\n/////////////////////////////////\r\n");
            DBG_PRINTF("MEDiThings VivaMayo Started 1.12C\r\n");
            DBG_PRINTF("/////////////////////////////////\r\n");

            power_control_set(ON);
            battery_timer_start();

            icm42670_init();
            nrf_delay_ms(2);

            DBG_PRINTF("ADV_START\r\n");
#if FEATURE_SECURE_CONNECTION
            advertising_start(erase_bonds);
#else
            advertising_start();
#endif
            DBG_PRINTF("ADV_DONE\r\n");

            ada2200_init();
            nrf_delay_ms(1);
            mcp4725_init();
            nrf_delay_ms(1);

            /* Set reset status in RAM only (no FDS write during boot) */
            m_reset_status = 1;
            m_config.reset_status = 1;
            LOG_PRINTF("START\r\n");

            /* W25Q32 Flash test - disabled, use cmd?99,0,0 manually */
            // w25q_test_timer_start();
        }
    } else {
        /* Button still pressed - increment counter and continue polling */
        cnt_s++;
        device_reset = false;

        if (cnt_s == 150) {
            /* Indicate long press threshold reached */
            uint32_t err_code = bsp_indication_set(BSP_INDICATE_USER_STATE_ON);
            (void)err_code;
        }
        power_ctrl_timers_start();
    }
}

/*==============================================================================
 * BSP EVENT HANDLER
 *============================================================================*/

void power_bsp_event_handler(bsp_event_t event)
{
    uint32_t err_code;

    switch (event)
    {
        case BSP_EVENT_SLEEP:
            go_sleep_mode_enter = true;
            DBG_PRINTF("BSP_EVENT_sleep\r\n");
            main_timer_start();
            break;

        case BSP_EVENT_DISCONNECT:
            err_code = sd_ble_gap_disconnect(m_conn_handle,
                                             BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
            if (err_code != NRF_SUCCESS) {
                m_reset_status = 2;
            } else {
                DBG_PRINTF("Disconnected connection handle %d\r\n", m_conn_handle);
            }
            break;

        case BSP_EVENT_WHITELIST_OFF:
            if (m_conn_handle == BLE_CONN_HANDLE_INVALID) {
                err_code = ble_advertising_restart_without_whitelist_wrapper();
                if (err_code != NRF_ERROR_INVALID_STATE) {
                    APP_ERROR_CHECK(err_code);
                }
            }
            break;

        case BSP_EVENT_KEY_2:
            break;

        case BSP_EVENT_POWER_CONTROL:
            if (processing == false) {
                DBG_PRINTF("SYSTEM OFF\r\n");
                err_code = bsp_indication_set(BSP_INDICATE_USER_STATE_ON);
                APP_ERROR_CHECK(err_code);
                go_device_power_off = true;
                main_timer_start();
            } else {
                DBG_PRINTF("SYSTEM OFF FAIL\r\n");
            }
            break;

        default:
            break;
    }
}
