/*******************************************************************************
 TEST medi50  Dec 23
 ******************************************************************************/

#include "sdk_config.h"

#include <string.h>

#include "app_error.h"
#include "boards.h"
#include "nrf_fstorage.h"
#include "nrf_soc.h"
#include "nrf_strerror.h"
#include "sdk_config.h"
#include "nrf_fstorage_sd.h"
#include "nrf_delay.h"
#include "ble_gap.h"
#include "fds.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

#include "fstorage.h"
#include "nrf_pwr_mgmt.h"
#include "measurements.h"
#include "main.h"
#include "power/power_ctrl.h"
#include "debug_print.h"


/* File ID and Key used for the configuration record. */

#define CONFIG_FILE     (0x8010)
#define CONFIG_REC_KEY  (0x7010)

#define CONFIG_MAGIC_NUMBER_VALUE          (0x20231226)
config_data_t m_config;

extern bool go_device_power_off;
extern bool go_sleep_mode_enter;
extern bool go_NVIC_SystemReset;

/* Flag to check fds initialization. */
static bool volatile m_fds_initialized;

bool fds_flag_write = false;
/* A record containing dummy configuration data. */
static fds_record_t const m_dummy_record =
{
    .file_id           = CONFIG_FILE,
    .key               = CONFIG_REC_KEY,
    .data.p_data       = (void const *)&m_config,
    /* The length of a record is always expressed in 4-byte units (words). */
    .data.length_words = (sizeof(m_config) + 3) / sizeof(uint32_t),
};


/* 공장 입력 항목 1 */


/* 공장 입력 항목 2 */
//char        serial_number_dflt[12] = "2025AAMAY0FF";
//uint16_t   	pd_delay_us = 0;
//int8_t	reset_status=0;

//uint32_t	pd_adc_calibration_dflt_PD0[M_LED_NUM] = 
//	{1000, 1000, 1000, 1000, 1000, 1000,1000, 1000, 1000, 1000, 1000, 1000,1000, 1000, 1000, 1000, 1000, 1000,1000, 1000, 1000, 1000, 1000, 1000, /* PD01 */
//};
//uint32_t	pd_adc_calibration_dflt_PD1[M_LED_NUM] = 
//	{1000, 1000, 1000, 1000, 1000, 1000,1000, 1000, 1000, 1000, 1000, 1000,1000, 1000, 1000, 1000, 1000, 1000,1000, 1000, 1000, 1000, 1000, 1000, /* PD1 */
//};
//uint32_t	pd_adc_calibration_dflt_PD2[M_LED_NUM] = 
//	{1000, 1000, 1000, 1000, 1000, 1000,1000, 1000, 1000, 1000, 1000, 1000,1000, 1000, 1000, 1000, 1000, 1000,1000, 1000, 1000, 1000, 1000, 1000, /* MOD1 */
//};

///* 공장 입력 항목 5 */
//uint32_t dark_noise_for_pd_dflt[PD_NUM] = 	/*PD0, PD1, PD2, PD3, PD4, PD5, PD6, PD7, PD8, PD9, PD10, PD11, PD12, PD13, PD14, PD15, PD16, PD17, PD18, PD19, PD20,  */
//	{1111, 1111};


/* 공장 입력 항목 8 */
//int8_t	pd_adc_cnt_dflt = 8;		/* 8, 16, 24, 32 */
int8_t	reset_status_dflt =99;	
/* 공장 입력 항목 9 */
//uint16_t led_delay_us_dflt = 8000; 	/* 0 ~ 65535 */

/* 공장 입력 항목 10 */
//uint16_t pd_delay_us_dflt = 8000;		/* 0 ~ 65535 */

/* Static Passkey default */
uint8_t static_passkey_dflt[6] = "123456";

		
		
		
//		
//uint16_t led_power_dp_dflt[48] = {
//	//NULL, 42, 29, 41, 31, 28, 28, 42, 28, 39, 29, 27, 27, 42, 29, 40, 30, 28, 28, 40, 27, 38, 28, 25, 22
//	25,25,25,18,19,24,24,25,25,18,19,25,23,25,25,18,19,24,24,25,25,19,20,25,24,25,25,25,18,19,24,24,25,25,18,19,25,23,25,25,18,19,24,24,25,25,19,20
//};		
		
void fds_default_value_set(void)
{
	/* HW Number - empty (set via BLE command) */
	memset(m_config.hw_no, 0, 12);

	/* Serial Number */
	memcpy(m_config.serial_no, "2025AAAAT001", 12);

	/* Static Passkey */
	memcpy(m_config.static_passkey, static_passkey_dflt, 6);

	/* Bond data delete */
	m_config.bond_data_delete = 1;

	/* Reset status */
	m_config.reset_status = reset_status_dflt;

	/* Measurement parameters */
	m_config.pd_adc_cnt  = 8;
	m_config.pd_delay_us = 8000;
}


static volatile uint8_t fds_last_evt = 0xFF;

static void fds_evt_handler( fds_evt_t const *p_evt )
{
    fds_last_evt = p_evt->id;

    switch( p_evt->id )
    {
        case FDS_EVT_INIT:
            if( p_evt->result == NRF_SUCCESS )
            {
                m_fds_initialized = true;
            }
            break;

        case FDS_EVT_WRITE:
            {
                fds_flag_write = false;
            }
            break;

		case FDS_EVT_UPDATE:
			{
				fds_flag_write = false;

					if(go_device_power_off == true) {
						/* After flash writing completed, System Power Off */
						device_power_off();
					}
					if(go_sleep_mode_enter == true) {
						/* After flash writing completed, System go to Sleep Mode */
						sleep_mode_enter();
					}
					if(go_NVIC_SystemReset == true) {
						/* After flash writing completed, System Reset */
						printf("Off FDS_ENVET\r\n");
						NVIC_SystemReset(); //0112
					}
			}
			break;

		case FDS_EVT_DEL_RECORD:
			break;	

		case FDS_EVT_DEL_FILE:
			break;

		case FDS_EVT_GC:
			break;			

		default:
            break;
    }
}


/**@brief   Wait for fds to initialize. */
static void wait_for_fds_ready( void )
{
    uint32_t timeout = 0;
    while( !m_fds_initialized )
    {
        nrf_pwr_mgmt_run();
        nrf_delay_ms(1);
        timeout++;
        if (timeout > 3000) {  /* 3 second timeout */
            printf("[FDS] TIMEOUT!\r\n");
            break;
        }
    }
}


void config_load( void )
{
    ret_code_t rc;
    fds_record_desc_t desc = { 0 };
    fds_find_token_t  tok  = { 0 };
    uint8_t cfg_retry = 0;

 cfg_load_start:
    memset((char *)&desc, 0, sizeof(desc));
    memset((char *)&tok, 0, sizeof(tok));
    rc = fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &tok);
    DBG_PRINTF("[FDS] find rc=%u\r\n", rc);

    /* FDS may not be fully ready yet - retry before writing defaults */
    if (rc != NRF_SUCCESS && cfg_retry < 10) {
        cfg_retry++;
        DBG_PRINTF("[FDS] retry %u/10\r\n", cfg_retry);
        nrf_delay_ms(100);
        goto cfg_load_start;
    }

    if( rc == NRF_SUCCESS )
    {
        /* A config file is in flash. Let's update it. */
        fds_flash_record_t config = { 0 };

        /* Open the record and read its contents. */
        rc = fds_record_open(&desc, &config);
        if (rc != NRF_SUCCESS) {
            /* CRC error or corrupt record - delete and use defaults */
            DBG_PRINTF("[FDS] open ERR=%u, deleting\r\n", rc);
            (void)fds_record_delete(&desc);
            fds_gc();
            fds_default_value_set();
            goto cfg_load_write_new;
        }

        /* Copy the configuration from flash into m_config. */
        memcpy(&m_config, config.p_data, sizeof(config_data_t));

        /* Close the record when done reading. */
        rc = fds_record_close(&desc);
        APP_ERROR_CHECK(rc);

        DBG_PRINTF("[FDS] magic=0x%08X (expect 0x%08X)\r\n",
                   m_config.magic_number, CONFIG_MAGIC_NUMBER_VALUE);

        if( m_config.magic_number != (uint32_t)CONFIG_MAGIC_NUMBER_VALUE )
        { // first init
            DBG_PRINTF("[FDS] FORMAT! overwriting with defaults\r\n");
            rc = fds_record_delete(&desc);
            APP_ERROR_CHECK(rc);
            m_config.magic_number = CONFIG_MAGIC_NUMBER_VALUE;

            // default....
            fds_default_value_set();

            /* Write the updated record to flash. */
            rc = fds_record_update(&desc, &m_dummy_record);
            if( (rc != NRF_SUCCESS) && (rc == FDS_ERR_NO_SPACE_IN_FLASH) )
            {
                rc = fds_gc();
                APP_ERROR_CHECK(rc);
            }
            else
            {
                APP_ERROR_CHECK(rc);
            }
            goto cfg_load_start;
        }
        DBG_PRINTF("[FDS] Loaded OK\r\n");
    }
    else
    {
 cfg_load_write_new:
        DBG_PRINTF("[FDS] New - writing defaults\r\n");
        /* System config not found (or corrupt); write a new one. */
        m_config.magic_number = CONFIG_MAGIC_NUMBER_VALUE;

        // default....
        fds_default_value_set();

        fds_flag_write = true;
        rc = fds_record_write(&desc, &m_dummy_record);
        if (rc != NRF_SUCCESS) {
            DBG_PRINTF("[FDS] Write ERR=%u\r\n", rc);
            fds_flag_write = false;
        }
        while( fds_flag_write )
        {
            nrf_pwr_mgmt_run();
        }
        if( (rc != NRF_SUCCESS) && (rc == FDS_ERR_NO_SPACE_IN_FLASH) )
        {
            rc = fds_gc();
            APP_ERROR_CHECK(rc);
        }
        else
        {
            APP_ERROR_CHECK(rc);
        }
        NRF_LOG_FLUSH();
        goto cfg_load_start;
    }
}


void config_save( void )
{
    ret_code_t rc;
    fds_record_desc_t desc = { 0 };
    fds_find_token_t  tok  = { 0 };

    DBG_PRINTF("[CFG_SAVE] start\r\n");

    /* Skip if a previous FDS operation is still in progress (non-blocking) */
    if (fds_flag_write) {
        DBG_PRINTF("[CFG_SAVE] busy, skipped\r\n");
        return;
    }

    if( m_config.magic_number != (uint32_t)CONFIG_MAGIC_NUMBER_VALUE )
    {
        m_config.magic_number = CONFIG_MAGIC_NUMBER_VALUE;
    }

    memset((char *)&desc, 0, sizeof(desc));
    memset((char *)&tok, 0, sizeof(tok));
    rc = fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &tok);
    DBG_PRINTF("[CFG_SAVE] find rc=%u\r\n", rc);

    /* Debug: show what we're about to save */
    {
        char tmp[13] = {0};
        memcpy(tmp, m_config.hw_no, 12);
        DBG_PRINTF("[CFG_SAVE] hw='%s'\r\n", tmp);
        memcpy(tmp, m_config.serial_no, 12);
        DBG_PRINTF("[CFG_SAVE] sn='%s'\r\n", tmp);
    }

    if( rc == NRF_SUCCESS )
    {
        fds_flag_write = true;
        rc = fds_record_update(&desc, &m_dummy_record);
        DBG_PRINTF("[CFG_SAVE] update rc=%u\r\n", rc);
        if( rc == FDS_ERR_NO_SPACE_IN_FLASH )
        {
            fds_flag_write = false;
            rc = fds_gc();
            DBG_PRINTF("[CFG_SAVE] gc rc=%u, retry\r\n", rc);
            fds_flag_write = true;
            rc = fds_record_update(&desc, &m_dummy_record);
            DBG_PRINTF("[CFG_SAVE] retry rc=%u\r\n", rc);
        }
        if( rc != NRF_SUCCESS )
        {
            DBG_PRINTF("[CFG_SAVE] FAIL rc=%u\r\n", rc);
            fds_flag_write = false;
        }
    }
    else
    {
        DBG_PRINTF("[CFG_SAVE] not found, writing new\r\n");
        fds_flag_write = true;
        rc = fds_record_write(&desc, &m_dummy_record);
        DBG_PRINTF("[CFG_SAVE] write rc=%u\r\n", rc);
        if( rc != NRF_SUCCESS )
        {
            DBG_PRINTF("[CFG_SAVE] FAIL rc=%u\r\n", rc);
            fds_flag_write = false;
        }
    }

    DBG_PRINTF("[CFG_SAVE] done\r\n");
}


void fs_set_value(void)
{
	config_load();
}

void fs_storage_init(void)
{
    ret_code_t rc;

    /* Register first to receive an event when initialization is complete. */
    rc = fds_register(fds_evt_handler);
    APP_ERROR_CHECK(rc);

    rc = fds_init();
    APP_ERROR_CHECK(rc);

    /* Wait for fds to initialize. */
    wait_for_fds_ready();

    fds_stat_t stat = { 0 };
    rc = fds_stat(&stat);
    APP_ERROR_CHECK(rc);

    printf("[FDS] OK\r\n");
}

