volatile bool is_fds_initialized = false, is_fds_write_complete = false, is_fds_update_complete = false;
volatile bool is_fds_file_delete_complete = false, is_fds_gc_complete = false;
volatile bool is_fds_record_delete_complete = false;

// fds_record_t f_record;
/**
 * @brief A function to handle the events generated by user data storage module
 *
 * @params[in] - [1] p_evt - A pointer to the user data storage event
 *
 * @return - None
 *
 */
void user_data_event_handler(fds_evt_t const * p_evt)
{
  switch(p_evt->id)
  { 
    case FDS_EVT_INIT:

    is_fds_initialized = true;

    break;

    case FDS_EVT_WRITE:

    is_fds_write_complete = true;
          
    break; 

    case FDS_EVT_UPDATE:

    is_fds_update_complete = true;

    break;

    case FDS_EVT_DEL_RECORD:

    is_fds_record_delete_complete = true;

    break;

    case FDS_EVT_DEL_FILE:

    is_fds_file_delete_complete = true;

    break;

    case FDS_EVT_GC:

    is_fds_gc_complete = true;
     
    break;
  }
}

/**
 * @brief A function to flash storage module
 *
 * @params[in]  - None
 * @params[out] - None
 *
 * @return - error_code
 *
 */
void flash_storage_init(void)
{
    uint32_t fds_error_code;

    // memset(&f_record, 0x00, sizeof(f_record));
    memset(&nv_user_data, 0x00, sizeof(nv_user_data));
#ifdef EXIT_SIGN
    memset(&exit_sign_data,0x00,sizeof(exit_sign_data));
#endif
    // Register event handler
    fds_error_code = fds_register(user_data_event_handler);
    if (fds_error_code == FDS_SUCCESS) {
        uart_logf("FDS event handler registered successfully\r\n");
    } else {
        uart_logf("FDS register failed: %d\r\n", fds_error_code);
    }

    // Initialize FDS
    fds_error_code = fds_init();
    if (fds_error_code == FDS_SUCCESS) {
        uart_logf("FDS initialized, waiting for completion\r\n");
    } else {
        uart_logf("FDS init failed: %d\r\n", fds_error_code);
    }

    // Wait for initialization to complete
    while (!is_fds_initialized) {
        sd_app_evt_wait();
    }
    uart_logf("User data module initialization completed\r\n");
}

/**
 * @brief A function to store user data
 *
 * @params[in] -  None
 *
 * @params[out] - [1] p_desc - The descriptor of the record that was written. Pass NULL if you do not
 *                             need the descriptor.
 *
 * @return - error_code
 *
 */
uint32_t save_fds_data(uint16_t file_id, uint16_t record_key)
{
    uint32_t fds_error_code;
    fds_record_desc_t temp_desc;
    fds_record_t f_record;
    fds_record_chunk_t record_chunk;   // ✅ Create a chunk

    memset(&temp_desc, 0x00, sizeof(fds_record_desc_t));
    memset(&f_record, 0x00, sizeof(fds_record_t));
    memset(&record_chunk, 0x00, sizeof(fds_record_chunk_t));

    f_record.file_id = file_id;
    f_record.key     = record_key;

    switch (file_id)
    {
        case USER_DATA_FILE_ID:
        {
            switch (record_key)
            {
                case USER_DATA_RECORD_KEY:
                    memset(&nv_user_data, 0x00, sizeof(nv_user_data));
                    memcpy(&nv_user_data, &default_nv_user_data, sizeof(nv_user_data));

                    record_chunk.p_data       = &nv_user_data;
                    record_chunk.length_words = sizeof(nv_user_data) / 4;

                    f_record.data.p_chunks  = &record_chunk;
                    f_record.data.num_chunks = 1;
                    break;
            }
        } break;

#ifdef EXIT_SIGN
        case EIS_FILE_ID:
        {
            switch (record_key)
            {
                case EIS_AQI_KEY:
                    memset(&exit_sign_data.aqi_part, 0x00, sizeof(exit_sign_data.aqi_part));
                    memcpy(&exit_sign_data.aqi_part, &default_exit_sign_data.aqi_part, sizeof(exit_sign_data.aqi_part));

                    record_chunk.p_data       = &exit_sign_data.aqi_part;
                    record_chunk.length_words = sizeof(exit_sign_data.aqi_part) / 4;

                    f_record.data.p_chunks  = &record_chunk;
                    f_record.data.num_chunks = 1;
                    break;

                case EIS_NODE_KEY:
                    memset(&exit_sign_data.node_part, 0x00, sizeof(exit_sign_data.node_part));
                    memcpy(&exit_sign_data.node_part, &default_exit_sign_data.node_part, sizeof(exit_sign_data.node_part));

                    record_chunk.p_data       = &exit_sign_data.node_part;
                    record_chunk.length_words = sizeof(exit_sign_data.node_part) / 4;

                    f_record.data.p_chunks  = &record_chunk;
                    f_record.data.num_chunks = 1;
                    break;

                case EIS_LSD_KEY:
                    memset(&exit_sign_data.lsd_part, 0x00, sizeof(exit_sign_data.lsd_part));
                    memcpy(&exit_sign_data.lsd_part, &default_exit_sign_data.lsd_part, sizeof(exit_sign_data.lsd_part));

                    record_chunk.p_data       = &exit_sign_data.lsd_part;
                    record_chunk.length_words = sizeof(exit_sign_data.lsd_part) / 4;

                    f_record.data.p_chunks  = &record_chunk;
                    f_record.data.num_chunks = 1;
                    break;

                case EIS_POST_KEY:
                    memset(&exit_sign_data.post_part, 0x00, sizeof(exit_sign_data.post_part));
                    memcpy(&exit_sign_data.post_part, &default_exit_sign_data.post_part, sizeof(exit_sign_data.post_part));

                    record_chunk.p_data       = &exit_sign_data.post_part;
                    record_chunk.length_words = sizeof(exit_sign_data.post_part) / 4;

                    f_record.data.p_chunks  = &record_chunk;
                    f_record.data.num_chunks = 1;
                    break;

                case EIS_MOTION_KEY:
                    memset(&exit_sign_data.motion_part, 0x00, sizeof(exit_sign_data.motion_part));
                    memcpy(&exit_sign_data.motion_part, &default_exit_sign_data.motion_part, sizeof(exit_sign_data.motion_part));

                    record_chunk.p_data       = &exit_sign_data.motion_part;
                    record_chunk.length_words = sizeof(exit_sign_data.motion_part) / 4;

                    f_record.data.p_chunks  = &record_chunk;
                    f_record.data.num_chunks = 1;
                    break;
            }
        } break;
#endif
    }

    fds_error_code = fds_record_write(&temp_desc, &f_record);
    if (fds_error_code != FDS_SUCCESS)
        return fds_error_code;

    if (fds_error_code != FDS_SUCCESS)
        return fds_error_code;

    while (!is_fds_write_complete);

    fds_error_code = fds_gc();
    if (fds_error_code != FDS_SUCCESS)
        return fds_error_code;

    while (!is_fds_gc_complete);

    return FDS_SUCCESS;
}

/**
 * @brief A function to updated stored user data
 *
 * @params[in] -  None
 *
 * @params[out] - None
 *
 * @return - error_code
 *
 */
uint32_t update_fds_data(uint16_t file_id, uint16_t record_key)
{
    uint32_t fds_error_code;
    fds_record_desc_t desc;
    fds_find_token_t token;
    fds_flash_record_t record;
    fds_record_t f_record;
    fds_record_chunk_t record_chunk;   // ✅ Local chunk

    memset(&desc, 0x00, sizeof(desc));
    memset(&token, 0x00, sizeof(token));
    memset(&f_record, 0x00, sizeof(f_record));
    memset(&record_chunk, 0x00, sizeof(record_chunk));
    memset(&record, 0x00, sizeof(record));

    is_fds_update_complete = false;

    // Optional: run garbage collection before update
    fds_gc_run();

    // Find existing record
    fds_error_code = fds_record_find(file_id, record_key, &desc, &token);
    if (fds_error_code != FDS_SUCCESS)
    {
        return fds_error_code;
    }

    f_record.file_id = file_id;
    f_record.key     = record_key;

    switch (file_id)
    {
        case USER_DATA_FILE_ID:
        {
            switch (record_key)
            {
                case USER_DATA_RECORD_KEY:
                    record_chunk.p_data       = &nv_user_data;
                    record_chunk.length_words = sizeof(nv_user_data) / 4;
                    break;
            }
        } break;

#ifdef EXIT_SIGN
        case EIS_FILE_ID:
        {
            switch (record_key)
            {
                case EIS_AQI_KEY:
                    record_chunk.p_data       = &exit_sign_data.aqi_part;
                    record_chunk.length_words = sizeof(exit_sign_data.aqi_part) / 4;
                    break;

                case EIS_NODE_KEY:
                    record_chunk.p_data       = &exit_sign_data.node_part;
                    record_chunk.length_words = sizeof(exit_sign_data.node_part) / 4;
                    break;

                case EIS_LSD_KEY:
                    record_chunk.p_data       = &exit_sign_data.lsd_part;
                    record_chunk.length_words = sizeof(exit_sign_data.lsd_part) / 4;
                    break;

                case EIS_POST_KEY:
                    record_chunk.p_data       = &exit_sign_data.post_part;
                    record_chunk.length_words = sizeof(exit_sign_data.post_part) / 4;
                    break;

                case EIS_MOTION_KEY:
                    record_chunk.p_data       = &exit_sign_data.motion_part;
                    record_chunk.length_words = sizeof(exit_sign_data.motion_part) / 4;
                    break;
            }
        } break;
#endif
    }

    // ✅ Assign the chunk pointer and number of chunks
    f_record.data.p_chunks  = &record_chunk;
    f_record.data.num_chunks = 1;

    // Update record
    fds_error_code = fds_record_update(&desc, &f_record);
    if (fds_error_code != FDS_SUCCESS)
    {
        return fds_error_code;
    }

    while (!is_fds_update_complete)
    {
        sd_app_evt_wait();
    }

    // Optional garbage collection
    fds_error_code = fds_gc();
    if (fds_error_code != FDS_SUCCESS)
    {
        return fds_error_code;
    }

    while (!is_fds_gc_complete){
        sd_app_evt_wait();
    }
    return FDS_SUCCESS;

}

/**
 * @brief A function to load stored user data into config_data
 *
 * @params[in] -  None
 *
 * @params[out] - None
 *
 * @return - error_code
 *
 */
uint32_t load_fds_data(uint16_t file_id, uint16_t record_key)
{
  uint8_t i = 0;
  uint32_t fds_error_code;

  fds_record_desc_t desc;
  fds_flash_record_t record;
  fds_find_token_t token;

  memset(&desc, 0x00, sizeof(fds_record_desc_t));
  memset(&record, 0x00, sizeof(fds_flash_record_t));
  memset(&token, 0x00, sizeof(fds_find_token_t));

  fds_error_code = fds_record_find(file_id, record_key, &desc, &token);

  if(fds_error_code == FDS_SUCCESS)
  { 
      fds_error_code = fds_record_open(&desc, &record);

      if(fds_error_code == FDS_SUCCESS)
      {
        switch (file_id)
        {
            case USER_DATA_FILE_ID:{
                if(record_key == USER_DATA_RECORD_KEY){
                    memcpy(&nv_user_data, record.p_data, sizeof(nv_user_data));
                }
            }break;
#ifdef EXIT_SIGN
            case EIS_FILE_ID:{
                switch(record_key)
                {
                    case EIS_AQI_KEY:
                    memcpy(&exit_sign_data.aqi_part, record.p_data, sizeof(exit_sign_data.aqi_part));
                    break;

                    case EIS_NODE_KEY:
                    memcpy(&exit_sign_data.node_part, record.p_data, sizeof(exit_sign_data.node_part));
                    break;

                    case EIS_LSD_KEY:
                    memcpy(&exit_sign_data.lsd_part, record.p_data, sizeof(exit_sign_data.lsd_part));
                    break;

                    case EIS_POST_KEY:
                    memcpy(&exit_sign_data.post_part, record.p_data, sizeof(exit_sign_data.post_part));
                    break;

                    case EIS_MOTION_KEY:
                    memcpy(&exit_sign_data.motion_part, record.p_data, sizeof(exit_sign_data.motion_part));
                    break;
                }
            }break;
#endif
        }
          fds_error_code = fds_record_close(&desc);

          if(fds_error_code == FDS_SUCCESS)
          {
              return FDS_SUCCESS;
          }
      }
  }

  return fds_error_code;
}

/**
 * @brief A function to delete user data
 *
 * @params[in] - None
 *
 * @params[ou] - None
 *
 * @return error_code
 *
 */
uint32_t fds_delete_record(uint16_t file_id, uint16_t record_key)
{
  uint32_t fds_error_code;

  fds_record_desc_t desc;
  fds_find_token_t token;

  memset(&desc, 0x00, sizeof(fds_record_desc_t));
  memset(&token, 0x00, sizeof(fds_find_token_t));

  is_fds_record_delete_complete = false;
  is_fds_gc_complete = false;

  fds_error_code = fds_record_find( file_id, record_key, &desc, &token);

  if(fds_error_code != FDS_SUCCESS)
  {
    return fds_error_code;
  }
  else
  {
      fds_error_code = fds_record_delete(&desc);
      if(fds_error_code != FDS_SUCCESS)
        uart_logf("FDS ERR: %d, Line:%d, File:%s\r\n",fds_error_code,__LINE__,__FILE__);

      while(!is_fds_record_delete_complete);

      fds_error_code = fds_gc();
      if(fds_error_code != FDS_SUCCESS)
      {
        return fds_error_code;
      }

      while(!is_fds_gc_complete);

  }
  return FDS_SUCCESS;
}

/**
 * @brief A function to delete user file
 *
 * @params[in] - None
 *
 * @params[ou] - None
 *
 * @return error_code
 *
 */
uint32_t fds_delete_file(uint16_t file_id, uint16_t record_key)
{
    uint32_t fds_error_code;
    fds_record_desc_t desc;
    fds_find_token_t token;

    memset(&desc, 0x00, sizeof(fds_record_desc_t));
    memset(&token, 0x00, sizeof(fds_find_token_t));

    is_fds_record_delete_complete = false;
    is_fds_gc_complete = false;

    fds_error_code = fds_record_find( file_id, record_key, &desc, &token);
    if(fds_error_code != FDS_SUCCESS)
    {
      return fds_error_code;
    }
    else
    {
        fds_error_code = fds_file_delete(file_id);

        while(!is_fds_file_delete_complete);

        fds_error_code = fds_gc();
        if(fds_error_code != FDS_SUCCESS)
        {
          return fds_error_code;
        }

        while(!is_fds_gc_complete);

    }
    return FDS_SUCCESS;
}

/**
 * @brief A function to check if the data is already written
 *
 * @parmas[in] - None
 *
 * @params[out] - None
 *
 * @return - true/false
 *
 */
bool is_record_available(uint16_t file_id, uint16_t record_key)
{
  uint32_t fds_error_code;
  
  fds_record_desc_t  data_record_desc;
  fds_find_token_t data_token; 

  memset(&data_record_desc, 0x00, sizeof(fds_record_desc_t));
  memset(&data_token, 0x00, sizeof(fds_find_token_t));

  fds_error_code = fds_record_find( file_id, record_key, &data_record_desc, &data_token );
  if(fds_error_code != FDS_SUCCESS)
  {
      return false;
  }

  return true;

}

/**
* @brief Garbage collection
*/
void fds_gc_run(void)
{
  uint32_t fds_error_code;

  is_fds_gc_complete = false;

  fds_error_code = fds_gc();

  while(!is_fds_gc_complete);
}

/**@brief A function to load/store data all the configuration data
**/
void load_all_fds_data(void)
{

    uint16_t i = 0x00, j = 0x00;

    uint32_t error_code;

    if(!is_record_available(USER_DATA_FILE_ID,USER_DATA_RECORD_KEY))
    {
         error_code = save_fds_data(USER_DATA_FILE_ID, USER_DATA_RECORD_KEY);
         if(error_code != FDS_SUCCESS)
            NVIC_SystemReset();
    } else {
            error_code = load_fds_data(USER_DATA_FILE_ID, USER_DATA_RECORD_KEY);
            if(error_code != FDS_SUCCESS)
              NVIC_SystemReset();
    }
#ifdef EXIT_SIGN 
    for(i = EIS_AQI_KEY; i <= EIS_MOTION_KEY; i++ )
    {
        if(!is_record_available(EIS_FILE_ID, i))
        {
             error_code = save_fds_data(EIS_FILE_ID, i);
             if(error_code != FDS_SUCCESS)
              NVIC_SystemReset();
             j += 1;
        }
        else
        {
            error_code = load_fds_data(EIS_FILE_ID, i);
            if(error_code != FDS_SUCCESS)
              NVIC_SystemReset();
            
            if(i == EIS_AQI_KEY)
            {
                if(exit_sign_data.aqi_part.valid_signature != FLASH_PAGE_VALID)
                {
                    fds_delete_file(EIS_FILE_ID, i);
                    fds_gc_run();

                    error_code = save_fds_data(EIS_FILE_ID, i);
                    if(error_code != FDS_SUCCESS)
                        NVIC_SystemReset();
                }
            }
        }
    }
#endif
#if 0
    if(FW_VERSION != config_data.fw_version_num)
    {
        config_data.fw_version_num = FW_VERSION;
        error_code = user_data_module_update_stored_data(CONFIG_FILE_ID, CONFIG_RECORD_KEY);
        if(error_code != NRF_SUCCESS)
          NVIC_SystemReset();
    }
#endif
    if(j > 0)             // reset if the data is stored for the first time
      NVIC_SystemReset();

    // global_unix_time = nv_user_data.last_correct_unix_time;

    // uart_logf("loaded time from the flash: %d\r\n", global_unix_time);
}
