/*******************************************************************************
 * @file    cmd_parse.c
 * @brief   Command Parser Wrapper (Legacy Compatibility)
 * @author  Charles KWON <charleskwon@medithings.co.kr>
 * @date    2025-02-04
 * @copyright (c) 2025 Medithings Inc. All rights reserved.
 *
 * @details This file provides:
 *          - Legacy compatibility wrapper (received_command_process)
 *          - Utility functions (error handling, validation)
 *          - EEPROM read functions
 *
 *          Actual parsing is handled by mt_parser/parser.c
 *          Command handlers are in cmd/cmd.c
 ******************************************************************************/

#include "cmd_parse.h"
#include "debug_print.h"
#include "parser.h"
#include "i2c_manager.h"
#include "app_timer.h"
#include "config/device_config.h"
#include "ble/ble_data_tx.h"
#include "ble_nus.h"
#include "crc16.h"
#include "cat_interface.h"
#include "storage/dr_mem.h"
#include <stdarg.h>
#include <string.h>

/*==============================================================================
 * @section DEFINES Constants
 *============================================================================*/

#define err_code1 65535  /* length error */
#define err_code2 65534  /* activate error */
#define err_code3 65533  /* param error */
#define err_code4 65532  /* ? missing */
#define err_code5 65531  /* CMD wrong */
#define err_code6 65530  /* CRC wrong */

/*==============================================================================
 * @section EXTERN External Declarations
 *============================================================================*/

extern uint8_t m_reset_status;

/* Note: SERIAL_NO, bond_data_delete, m_static_passkey, m_pd_adc_cnt,
   m_pd_delay_us, m_life_cycle are declared in device_config.h */

/* Defined in measurements.h */
extern uint16_t led_pd_dac_v[];

/* Defined in main.c */
extern char ble_tx_buffer[];
extern volatile bool processing;
extern bool ble_got_new_data;

/* BLE buffer (defined in ble_data_tx.c) */
extern uint8_t ble_bin_buffer[];

/* Parser globals (defined in parser.c) */
extern dr_platform_if_t g_plat;
extern bool g_log_enable;

/*==============================================================================
 * @section GLOBALS Global Variables (used by other modules)
 *============================================================================*/

uint8_t resetCount = 0;   /**< Reset counter */
bool info4 = false;       /**< Additional info flag for PD Full mode */

/*==============================================================================
 * @section STATIC Static Variables
 *============================================================================*/

static uint32_t processing_start_tick = 0;

/*==============================================================================
 * @section UTIL Utility Functions
 *============================================================================*/

/**
 * @brief Internal log function for parser
 */
static void log_printf(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    vprintf(fmt, args);
    va_end(args);
}

/*==============================================================================
 * @section CRC CRC Functions
 *============================================================================*/

bool crc16_check(uint8_t const *p_data, uint32_t data_len, uint16_t expected_crc)
{
    uint16_t computed_crc = crc16_compute(p_data, data_len, NULL);
    return (computed_crc == expected_crc);
}

bool crc16_check_packet(uint8_t const *packet, uint32_t packet_len)
{
    if (packet_len < 2) return false;

    uint32_t data_len = packet_len - 2;
    uint16_t expected_crc = (packet[packet_len - 1] << 8) | packet[packet_len - 2];

    return crc16_check(packet, data_len, expected_crc);
}

/*==============================================================================
 * @section ERROR Error Handling Functions
 *============================================================================*/

bool length_error(const char *cmd, uint8_t target_length, uint8_t length)
{
    if (target_length == length) {
        return true;
    }

    char resp_error[4];
    resp_error[0] = 'r';
    resp_error[1] = cmd[1];
    resp_error[2] = cmd[2];
    resp_error[3] = '!';

    single_format_data(ble_bin_buffer, resp_error, err_code1);
    binary_tx_handler(ble_bin_buffer, 3);
    return false;
}

bool activate_error(const char *cmd, bool device_status)
{
    if (device_status == true) {
        return true;
    }

    char resp_error[4];
    resp_error[0] = 'r';
    resp_error[1] = cmd[1];
    resp_error[2] = cmd[2];
    resp_error[3] = '!';

    single_format_data(ble_bin_buffer, resp_error, err_code2);
    binary_tx_handler(ble_bin_buffer, 3);
    return false;
}

void param_error(const char *cmd)
{
    char resp_error[4];
    resp_error[0] = 'r';
    resp_error[1] = cmd[1];
    resp_error[2] = cmd[2];
    resp_error[3] = '!';

    single_format_data(ble_bin_buffer, resp_error, err_code3);
    binary_tx_handler(ble_bin_buffer, 3);
}

void quest_error(const char *cmd)
{
    char resp_error[4];
    const char pass_init[6] = "123456";

    if ((cmd[0] == '*') && (cmd[1] == '*') && (cmd[2] == '*') && (cmd[3] == '*')) {
        if (dr_memWrite("passkey", (uint8_t *)pass_init, 6) != NRF_SUCCESS) {
            DBG_PRINTF("ERR!!! passkey write fail\r\n\r\n");
        }

        resp_error[0] = '*';
        resp_error[1] = cmd[1];
        resp_error[2] = cmd[2];
        resp_error[3] = '*';
        single_format_data(ble_bin_buffer, resp_error, err_code4);
        binary_tx_handler(ble_bin_buffer, 3);
    } else {
        resp_error[0] = 'r';
        resp_error[1] = cmd[1];
        resp_error[2] = cmd[2];
        resp_error[3] = '!';

        single_format_data(ble_bin_buffer, resp_error, err_code4);
        binary_tx_handler(ble_bin_buffer, 3);
    }
}

/*==============================================================================
 * @section INIT_READ Initial Values Read (via dr_mem API)
 *============================================================================*/

ret_code_t eeprom_init_values_read(void)
{
    ret_code_t err_code;

    /* FDS entries: Serial Number (12B, AES) */
    err_code = dr_memRead("serial_no", (uint8_t *)SERIAL_NO, 12);
    if (err_code != NRF_SUCCESS) return err_code;
    DBG_PRINTF("\r\n SN:%s \r\n", SERIAL_NO);

    /* FDS entries: Passkey (6B, AES) */
    err_code = dr_memRead("passkey", (uint8_t *)m_static_passkey, 6);
    if (err_code != NRF_SUCCESS) return err_code;
    DBG_PRINTF("\r\n passkey-0 :%s \n", m_static_passkey);

    /* FDS entries: Bond data delete (1B) */
    {
        uint8_t raw = 0;
        err_code = dr_memRead("bond_delete", &raw, 1);
        if (err_code != NRF_SUCCESS) return err_code;
        bond_data_delete = (raw != 0);
    }
    DBG_PRINTF("\r\n bond_data_delete :%d \n", bond_data_delete);

    /* FDS entries: Reset status (1B) */
    err_code = dr_memRead("reset_status", &m_reset_status, 1);
    if (err_code != NRF_SUCCESS) return err_code;

    /* FDS entries: PD ADC count (1B) */
    err_code = dr_memRead("pd_adc_cnt", &m_pd_adc_cnt, 1);
    if (err_code != NRF_SUCCESS) return err_code;
    if (m_pd_adc_cnt == 0 || m_pd_adc_cnt >= 255) {
        m_pd_adc_cnt = 8;
    }

    /* FDS entries: PD delay (2B) */
    err_code = dr_memRead("pd_delay", &m_pd_delay_us, 2);
    if (err_code != NRF_SUCCESS) return err_code;
    if (m_pd_delay_us < 5000 || m_pd_delay_us > 30000) {
        m_pd_delay_us = 8000;
    }

    /* W25Q32 entries: AGC Gain array (96B) */
    err_code = dr_memRead("agc_gain", led_pd_dac_v, 96);
    if (err_code != NRF_SUCCESS) return err_code;

    /* W25Q32 entries: Life cycle (4B) */
    err_code = dr_memRead("life_cycle", &m_life_cycle, 4);
    if (err_code != NRF_SUCCESS) return err_code;

    DBG_PRINTF("\r\n m_life_cycle:%u, m_pd_delay_us:%u, m_pd_adc_cnt:%u \r\n",
               m_life_cycle, m_pd_delay_us, m_pd_adc_cnt);

    return NRF_SUCCESS;
}

/*==============================================================================
 * @section API Main Entry Point
 *============================================================================*/

/**
 * @brief Process received command from UART or BLE
 * @details Initializes parser on first call, then delegates to dr_cmd_parser
 */
void received_command_process(uint8_t const *data_array, which_cmd_t cmd_t, uint8_t length)
{
    uint8_t r_data[BLE_NUS_MAX_DATA_LEN] = {0};
    int parser_result;

    (void)cmd_t;  /* Currently not used by new parser */

    ble_got_new_data = true;
    memset(ble_tx_buffer, 0, BLE_NUS_MAX_DATA_LEN);

    /* Copy data to local buffer */
    for (uint16_t i = 0; i < length; i++) {
        r_data[i] = data_array[i];
    }

    DBG_PRINTF("data : %s\r\n", r_data);
    DBG_PRINTF("Length : %d\r\n", length);

    /* Initialize parser (once) */
    static bool parser_initialized = false;

    if (!parser_initialized) {
        g_plat.log = log_printf;
        g_plat.tx_bin = binary_tx_handler;
        g_plat.crc_check = true;   /* CRC enabled */
        g_log_enable = true;

        parser_initialized = true;
        DBG_PRINTF(">>> Parser initialized (mt_parser)\r\n");
    }

    /* Check if already processing */
    if (processing == true) {
        uint32_t now = app_timer_cnt_get();

        if (processing_start_tick == 0) {
            processing_start_tick = now;
        }

        /* Timeout check (5 seconds) */
        if (app_timer_cnt_diff_compute(now, processing_start_tick) > APP_TIMER_TICKS(5000)) {
            processing = false;
            processing_start_tick = 0;
            DBG_PRINTF("processing timeout -> force reset to false\r\n");
        } else {
            DBG_PRINTF("Busy - command ignored\r\n");
            return;
        }
    }

    /* Call mt_parser */
    parser_result = dr_cmd_parser(r_data, length);

    if (parser_result > 0) {
        DBG_PRINTF(">>> Handled by mt_parser (result=%d)\r\n", parser_result);
    } else if (parser_result == 9) {
        DBG_PRINTF(">>> CRC/Parse error\r\n");
    } else {
        DBG_PRINTF(">>> Unknown command\r\n");
    }
}
