/*******************************************************************************
 * @file    main.c
 * @brief   MEDiThings VivaMayo - Main Application Entry Point
 * @author  Charles KWON <charleskwon@medithings.co.kr>
 * @date    2025-01-30
 * @copyright (c) 2025 Medithings Inc. All rights reserved.
 *
 * @version 1.17
 * @note    2025-01-30 Refactored into modular structure (Charles KWON)
 * @note    2025-12-31 Added comprehensive function documentation (Charles KWON)
 * @note    2025-11-27 Firmware cleanup and refactoring (Charles KWON)
 ******************************************************************************/

#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "debug_print.h"
#include "app_uart.h"

/* Nordic SDK */
#include "nordic_common.h"
#include "nrf.h"
#include "nrf_gpio.h"
#include "nrf_sdh.h"
#include "nrf_sdh_soc.h"
#include "nrf_sdh_ble.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_delay.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "app_timer.h"
#include "app_error.h"
#include "bsp.h"
#include "bsp_btn_ble.h"
#include "ble_nus.h"

/* Application Modules */
#include "ble/ble_core.h"
#include "ble/ble_services.h"
#include "ble/ble_data_tx.h"
#include "power/power_ctrl.h"
#include "peripheral/uart_handler.h"
#include "config/device_config.h"

#if FEATURE_SECURE_CONNECTION
#include "ble/ble_security.h"
#include "nrf_ble_lesc.h"
#endif

/* Hardware and Measurement Modules */
#include "main.h"
#include "main_timer.h"
#include "battery_saadc.h"
#include "measurements.h"
#include "full_agc.h"
#include "meas_pd_voltage_simple.h"
#include "meas_pd_voltage_half.h"
/* #include "meas_pd_voltage_full.h" */  /* Moved to unuse/ - FEATURE_PRINTF=0, not used */
#include "meas_pd_voltage_custom.h"
#include "meas_pd_imm.h"
#include "meas_pd_48.h"
#include "power_control.h"
#include "cat_interface.h"
#include "fstorage.h"
#include "drivers/w25q32/w25q32.h"

/* Crypto */
#include "nrf_crypto.h"

/*******************************************************************************
 * @section BUILD_CONFIG Build Configuration
 * @brief   Compile-time feature flags and debug settings
 * @details Controls boot mode selection between minimal (Power+BLE only) and
 *          full initialization (includes EEPROM and all peripherals).

*          Set DEBUG_MINIMAL_BOOT=1 for rapid debugging without EEPROM dependency.
 ******************************************************************************/

#define DEBUG_MINIMAL_BOOT  1   /**< 1: Power+BLE only (no EEPROM), 0: Full boot */

/*******************************************************************************
 * @section CONSTANTS Symbolic Constants
 * @brief   Application-wide constant definitions
 * @details Magic numbers and compile-time constants used for error handling,
 *          fault detection, and system-level operations.
 ******************************************************************************/

#define DEAD_BEEF   0xDEADBEEF

/*******************************************************************************
 * @section GLOBALS Global Variables
 * @brief   Shared runtime state and data buffers
 * @details BLE transmission buffers, command type state, and cross-module
 *          flags. External declarations reference state from other modules.
 * @warning Global state should be accessed with care in interrupt context.
 ******************************************************************************/

char ble_tx_buffer[BLE_NUS_MAX_DATA_LEN];
uint16_t ble_bin_buff[BLE_NUS_MAX_DATA_LEN/2];
which_cmd_t cmd_type_t;

/* External state flags from other modules */
extern bool ble_got_new_data;
extern bool motion_data_once;
extern bool adc_enabled;
extern bool con_single;
extern bool info4;
extern uint8_t add_cycle;
extern bool motion_raw_data_enabled;

/*******************************************************************************
 * @section FWD_DECL Forward Declarations
 * @brief   Static function prototypes
 * @details Internal initialization and handler functions declared here for
 *          proper ordering. Visibility limited to this translation unit.
 ******************************************************************************/

static void timers_init(void);
static void log_init(void);
static void power_management_init(void);
static void buttons_leds_init(bool * p_erase_bonds);
#if !DEBUG_MINIMAL_BOOT
static void gpio_init(void);
#endif
static void idle_state_handle(void);

/*******************************************************************************
 * @section ASSERT Assert Handler
 * @brief   System fault callback for SDK assertions
 * @details Invoked by Nordic SDK on fatal errors. Provides fault location
 *          (file and line) for debugging via app_error_handler.
 ******************************************************************************/

void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
{
    app_error_handler(DEAD_BEEF, line_num, p_file_name);
}

/*******************************************************************************
 * @section INIT Initialization Functions
 * @brief   System and peripheral initialization routines
 * @details Configures logging, power management, timers, and BSP components.
 *          Call order is critical - see main() for proper sequencing.
 ******************************************************************************/

static void log_init(void)
{
    ret_code_t err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);
    NRF_LOG_DEFAULT_BACKENDS_INIT();
}

static void power_management_init(void)
{
    ret_code_t err_code;
    err_code = nrf_pwr_mgmt_init();
    APP_ERROR_CHECK(err_code);
}

static void timers_init(void)
{
    ret_code_t err_code = app_timer_init();
    APP_ERROR_CHECK(err_code);

    /* Power control timers */
    power_ctrl_timers_init();

    /* Application timers */
    main_timer_init();
    battery_timer_init();
    imm_check_timer_init();
    m48_check_timer_init();
    full_agc_timer_init();
    full_agc_send_timer_init();
    mea_send_timer_init();
    power_timer_init();
    w25q_test_timer_init();

/* full_timer_init() - Moved to unuse/, FEATURE_PRINTF=0 so not used */
}

static void buttons_leds_init(bool * p_erase_bonds)
{
    bsp_event_t startup_event;

    uint32_t err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, power_bsp_event_handler);
    APP_ERROR_CHECK(err_code);

    err_code = bsp_btn_ble_init(NULL, &startup_event);
    APP_ERROR_CHECK(err_code);

    *p_erase_bonds = (startup_event == BSP_EVENT_CLEAR_BONDING_DATA);
}

/*******************************************************************************
 * @section PWR_HOLD Power Hold Initialization
 * @brief   Latches power supply on boot
 * @details Configures P0.08 (POWER_HOLD) as output HIGH to maintain VCC.
 *          CRITICAL: Must be the first call in main() - any delay risks
 *          power loss if button is released before latch is set.
 * @note    Uses direct register access for minimum latency.
 ******************************************************************************/
static void power_hold_init(void)
{
    /* P0.08 = POWER_HOLD, configure as output and set HIGH to maintain power */
    NRF_P0->DIRSET = (1 << 8);
    NRF_P0->OUTSET = (1 << 8);
}

/*******************************************************************************
 * @section MIN_GPIO Minimal GPIO Initialization (Debug Mode)
 * @brief   Reduced GPIO setup for rapid debugging
 * @details Initializes only essential pins: POWER_BUTTON input, POWER_HOLD
 *          output, and power control GPIOs. Skips LEDs, PD array, gain
 *          switches, and EEPROM control for faster boot.
 * @pre     DEBUG_MINIMAL_BOOT must be set to 1
 ******************************************************************************/
static void minimal_gpio_init(void)
{
    nrf_gpio_cfg_input(POWER_BUTTON, NRF_GPIO_PIN_NOPULL);
    nrf_gpio_cfg_output(POWER_HOLD);
    nrf_gpio_pin_set(POWER_HOLD);
    power_gpio_init();
    LOG_PRINTF("[GPIO] Minimal OK\r\n");
}

/*******************************************************************************
 * @section MIN_CFG Default Configuration Loader (Debug Mode)
 * @brief   Loads hardcoded defaults bypassing EEPROM
 * @details Sets factory defaults for serial number, passkey, PD timing,
 *          and bonding state. Used when EEPROM is unavailable or for
 *          rapid iteration during development.
 * @pre     DEBUG_MINIMAL_BOOT must be set to 1
 ******************************************************************************/
static void load_default_config(void)
{
    /* Direct assignment of variables defined in device_config.h */
    memset(SERIAL_NO, 0, sizeof(SERIAL_NO));
    memcpy(SERIAL_NO, "2025VIVAM00001", 14);

    memset(m_static_passkey, 0, sizeof(m_static_passkey));
    memcpy(m_static_passkey, "123456", 6);

    m_pd_delay_us    = 8000;
    m_pd_adc_cnt     = 8;
    bond_data_delete = true;

    LOG_PRINTF("[CFG] Default (S/N=%s)\r\n", SERIAL_NO);
}

/*******************************************************************************
 * @section FULL_GPIO Full GPIO Initialization (Production Mode)
 * @brief   Complete peripheral GPIO configuration
 * @details Initializes all hardware interfaces: LEDs, photodiode array (PD),
 *          trigger switches, AGC gain control, power management, and EEPROM.
 *          All outputs are set to safe default states (LEDs off, PD off).
 * @pre     DEBUG_MINIMAL_BOOT must be set to 0
 ******************************************************************************/
#if !DEBUG_MINIMAL_BOOT
static void gpio_init(void)
{
    nrf_gpio_cfg_input(POWER_BUTTON, NRF_GPIO_PIN_NOPULL);

    LED_CONFIG();
    LED_ALLOFF();

    PD_CONFIG();
    PD_ALLOFF();

    trig_r_CONFIG();
    trig_SW(false);

    GAIN_SW_CONFIG();
    AGC_GAIN_SW(false);

    power_gpio_init();
    eeprom_control(OFF);
}
#endif

/*******************************************************************************
 * @section IDLE Idle State Handler
 * @brief   Low-power idle loop processing
 * @details Handles security operations (LESC if enabled), flushes NRF_LOG
 *          buffer, then enters System ON sleep via nrf_pwr_mgmt_run().
 *          CPU wakes on any enabled interrupt (BLE, timer, GPIO).
 ******************************************************************************/

static void idle_state_handle(void)
{
#if FEATURE_SECURE_CONNECTION
    security_idle_state_handle();
#endif

    if (NRF_LOG_PROCESS() == false) {
        nrf_pwr_mgmt_run();
    }
}

/*******************************************************************************
 * @section MAIN Application Entry Point
 * @brief   System initialization and main loop
 * @details Boot sequence: Power latch → UART → Logging → GPIO → Timers →
 *          Config → BSP → Power Mgmt → BLE Stack → GAP → GATT → Services →
 *          Advertising → Connection Params → Power Button Handler.
 *          Main loop runs idle_state_handle() for low-power operation.
 * @note    Initialization order is critical for proper hardware bringup.
 ******************************************************************************/

/* LED slow blink macro (approximately 0.5 second period) */
#define LED_BLINK() do { \
    NRF_P0->OUTSET = (1 << 12); \
    for (volatile uint32_t _d = 0; _d < 1000000; _d++); \
    NRF_P0->OUTCLR = (1 << 12); \
    for (volatile uint32_t _d = 0; _d < 1000000; _d++); \
} while(0)

#define LED_PAUSE() do { \
    for (volatile uint32_t _d = 0; _d < 2000000; _d++); \
} while(0)

int main(void)
{
#if FEATURE_SECURE_CONNECTION
    bool erase_bonds_local = false;
#endif

    /* Configure LED output (P0.12) */
    NRF_P0->DIRSET = (1 << 12);

    power_hold_init();

    if (power_off_duble_prohibit) return 0;
    cnt_s = 0;

    uart_handler_init();
    nrf_delay_ms(100);  /* Wait for UART peripheral stabilization */
    log_init();

    g_log_enable = true;  /* Enable boot logging (set to false to disable boot logs) */

    LOG_PRINTF("\r\n\r\n");
    LOG_PRINTF("========================================\r\n");
    LOG_PRINTF(" VivaMayo UART OK\r\n");
    LOG_PRINTF("========================================\r\n");

#if DEBUG_MINIMAL_BOOT
    LOG_PRINTF("[1] GPIO (minimal)\r\n");
    minimal_gpio_init();
#else
    LOG_PRINTF("[1] GPIO (full)\r\n");
    gpio_init();
#endif
    info4 = false;

    LOG_PRINTF("[2] Timers\r\n");
    timers_init();

    LOG_PRINTF("[4] Buttons/LEDs\r\n");
#if FEATURE_SECURE_CONNECTION
    buttons_leds_init(&erase_bonds_local);
    erase_bonds = erase_bonds_local;
#else
    bool dummy_erase;
    buttons_leds_init(&dummy_erase);
#endif

    LOG_PRINTF("[5] PWR\r\n"); nrf_delay_ms(10);
    power_management_init();
    LOG_PRINTF("[6] BLE\r\n"); nrf_delay_ms(10);
    ble_stack_init();

    /* Flash Storage - must be after BLE stack (SoftDevice required) */
    /* and before GAP params (to use loaded config for device name) */
    LOG_PRINTF("[6.5] FDS\r\n"); nrf_delay_ms(10);
    fs_storage_init();
    config_load();

    LOG_PRINTF("[6.6] Config\r\n");
    load_device_configuration();

    /* W25Q32 Flash - NOT initialized during boot
     * Initialize via BLE command after advertising starts
     * (부팅 시 SPIM + BSP 이벤트 충돌로 SYSTEM OFF 발생 방지) */

    LOG_PRINTF("[7] GAP\r\n"); nrf_delay_ms(10);
    gap_params_init();
    gatt_init();
    services_init();
    LOG_PRINTF("[8] ADV\r\n"); nrf_delay_ms(10);
    advertising_init();
    conn_params_init();
    power_ctrl_timers_start();
    /* advertising_start() is invoked from power_ctrl.c after 5ms delay */

    nrf_delay_ms(20);
    LOG_PRINTF("=== READY ===\r\n");

    /*----------------------------------------------------------
     * Main Loop: Idle State Handler
     *----------------------------------------------------------*/
    for (;;)
    {
        idle_state_handle();
    }
}
