/*
 * This program source code file is part of the KTag project.
 *
 * 🛡️ <https://ktag.clubk.club> 🃞
 *
 * Copyright © 2024-2025 Joseph P. Kearney and the KTag developers.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
 * details.
 *
 * There should be a copy of the GNU Affero General Public License in the LICENSE
 * file in the root of this repository.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <string.h>
#include <SystemK.h>
#include <NVM.h>

static const uint8_t UNINTIALIZED_UINT8 = UINT8_MAX;

static uint8_t Cached_Team_ID = UNINTIALIZED_UINT8;
static uint8_t Cached_Player_ID = UNINTIALIZED_UINT8;
static uint8_t Cached_Weapon_ID = UNINTIALIZED_UINT8;
static uint8_t Cached_Max_Health = UNINTIALIZED_UINT8;
static uint8_t Cached_N_Special_Weapons_On_Reentry = UNINTIALIZED_UINT8;

SystemKResult_T SETTINGS_get_uint8_t(SystemKSettingID_T id, uint8_t *value)
{
    SystemKResult_T result = SYSTEMK_RESULT_UNSPECIFIED_FAILURE;
    char *key = "";
    uint8_t *cached_value = NULL;

    switch (id)
    {
    case SYSTEMK_SETTING_IS_RIGHT_HANDED:
        key = "Is_Right_Handed";
        break;

    case SYSTEMK_SETTING_AUDIO_VOLUME:
        key = "Audio_Volume";
        break;

    case SYSTEMK_SETTING_TEAMID:
        if (Cached_Team_ID != UNINTIALIZED_UINT8)
        {
            *value = Cached_Team_ID;
            result = SYSTEMK_RESULT_SUCCESS;
        }
        else
        {
            key = "Team_ID";
            cached_value = &Cached_Team_ID;
        }
        break;

    case SYSTEMK_SETTING_PLAYERID:
        if (Cached_Player_ID != UNINTIALIZED_UINT8)
        {
            *value = Cached_Player_ID;
            result = SYSTEMK_RESULT_SUCCESS;
        }
        else
        {
            key = "Player_ID";
            cached_value = &Cached_Player_ID;
        }
        break;

    case SYSTEMK_SETTING_WEAPONID:
        if (Cached_Weapon_ID != UNINTIALIZED_UINT8)
        {
            *value = Cached_Weapon_ID;
            result = SYSTEMK_RESULT_SUCCESS;
        }
        else
        {
            key = "Weapon_ID";
            cached_value = &Cached_Weapon_ID;
        }
        break;

    case SYSTEMK_SETTING_MAX_HEALTH:
        if (Cached_Max_Health != UNINTIALIZED_UINT8)
        {
            *value = Cached_Max_Health;
            result = SYSTEMK_RESULT_SUCCESS;
        }
        else
        {
            key = "Max_Health";
            cached_value = &Cached_Max_Health;
        }
        break;

    case SYSTEMK_SETTING_N_SPECIAL_WEAPONS_ON_REENTRY:
        if (Cached_N_Special_Weapons_On_Reentry != UNINTIALIZED_UINT8)
        {
            *value = Cached_N_Special_Weapons_On_Reentry;
            result = SYSTEMK_RESULT_SUCCESS;
        }
        else
        {
            key = "N_Special_Weapons_On_Reentry";
            cached_value = &Cached_N_Special_Weapons_On_Reentry;
        }
        break;

    default:
        result = SYSTEMK_RESULT_WRONG_DATATYPE;
        break;
    }

    if (result != SYSTEMK_RESULT_SUCCESS)
    {
        result = KV_Get_Value_uint8(CONFIG_FILE, key, value);

        if (result != SYSTEMK_RESULT_SUCCESS)
        {
            result = KV_Get_Value_uint8(DEFAULT_CONFIG_FILE, key, value);

            if (result == SYSTEMK_RESULT_SUCCESS)
            {
                (void)KV_Set_Value_uint8(CONFIG_FILE, key, value);
            }
        }

        // Save the cached value, if necessary.
        if ((cached_value != NULL) && (result == SYSTEMK_RESULT_SUCCESS))
        {
            *cached_value = *value;
        }
    }

    return result;
}

SystemKResult_T SETTINGS_set_uint8_t(SystemKSettingID_T id, uint8_t value)
{
    SystemKResult_T result = SYSTEMK_RESULT_SUCCESS;

    switch (id)
    {
    case SYSTEMK_SETTING_IS_RIGHT_HANDED:
        result = KV_Set_Value_uint8(CONFIG_FILE, "Is_Right_Handed", &value);
        break;

    case SYSTEMK_SETTING_AUDIO_VOLUME:
        result = KV_Set_Value_uint8(CONFIG_FILE, "Audio_Volume", &value);
        break;

    case SYSTEMK_SETTING_TEAMID:
        Cached_Team_ID = value;
        result = KV_Set_Value_uint8(CONFIG_FILE, "Team_ID", &value);
        break;

    case SYSTEMK_SETTING_PLAYERID:
        Cached_Player_ID = value;
        result = KV_Set_Value_uint8(CONFIG_FILE, "Player_ID", &value);
        break;

    case SYSTEMK_SETTING_WEAPONID:
        Cached_Weapon_ID = value;
        result = KV_Set_Value_uint8(CONFIG_FILE, "Weapon_ID", &value);
        break;

    case SYSTEMK_SETTING_MAX_HEALTH:
        Cached_Max_Health = value;
        result = KV_Set_Value_uint8(CONFIG_FILE, "Max_Health", &value);
        break;

    case SYSTEMK_SETTING_N_SPECIAL_WEAPONS_ON_REENTRY:
        Cached_N_Special_Weapons_On_Reentry = value;
        result = KV_Set_Value_uint8(CONFIG_FILE, "N_Special_Weapons_On_Reentry", &value);
        break;

    default:
        result = SYSTEMK_RESULT_WRONG_DATATYPE;
        break;
    }

    return result;
}

SystemKResult_T SETTINGS_get_uint32_t(SystemKSettingID_T id, uint32_t *value)
{
    SystemKResult_T result = SYSTEMK_RESULT_SUCCESS;
    char *key = "";

    switch (id)
    {
    case SYSTEMK_SETTING_DEVICE_TYPE:
        *value = BLE_DEVICE_TYPE_32ESPECIAL;
        return result;
        break;

    case SYSTEMK_SETTING_T_START_GAME_in_ms:
        key = "T_Start_Game_in_ms";
        break;

    case SYSTEMK_SETTING_T_GAME_LENGTH_in_ms:
        key = "T_Game_Length_in_ms";
        break;

    default:
        result = SYSTEMK_RESULT_WRONG_DATATYPE;
        break;
    }

    if (result == SYSTEMK_RESULT_SUCCESS)
    {
        result = KV_Get_Value_uint32(CONFIG_FILE, key, value);

        if (result != SYSTEMK_RESULT_SUCCESS)
        {
            result = KV_Get_Value_uint32(DEFAULT_CONFIG_FILE, key, value);

            if (result == SYSTEMK_RESULT_SUCCESS)
            {
                (void)KV_Set_Value_uint32(CONFIG_FILE, key, value);
            }
        }
    }

    return result;
}

SystemKResult_T SETTINGS_set_uint32_t(SystemKSettingID_T id, uint32_t value)
{
    SystemKResult_T result = SYSTEMK_RESULT_SUCCESS;

    switch (id)
    {
    case SYSTEMK_SETTING_T_START_GAME_in_ms:
        result = KV_Set_Value_uint32(CONFIG_FILE, "T_Start_Game_in_ms", &value);
        break;

    case SYSTEMK_SETTING_T_GAME_LENGTH_in_ms:
        result = KV_Set_Value_uint32(CONFIG_FILE, "T_Game_Length_in_ms", &value);
        break;

    default:
        result = SYSTEMK_RESULT_WRONG_DATATYPE;
        break;
    }

    return result;
}

SystemKResult_T SETTINGS_get_device_name(char* name)
{
    char buffer[KV_MAX_VALUE_LENGTH];
    SystemKResult_T result = KV_Get_Value_string(CONFIG_FILE, "Device_Name", buffer);

    if (result == SYSTEMK_RESULT_SUCCESS)
    {
        memcpy(name, buffer, SYSTEMK_MAX_CHARS_IN_DEVICE_NAME);
        buffer[SYSTEMK_MAX_CHARS_IN_DEVICE_NAME] = 0x00;
    }

    return result;
}

SystemKResult_T SETTINGS_set_device_name(char* name)
{
    SystemKResult_T result = KV_Set_Value_string(CONFIG_FILE, "Device_Name", name);
    return result;
}

// Settings are saved on change in this implementation.
SystemKResult_T SETTINGS_Save(void)
{
    return SYSTEMK_RESULT_SUCCESS;
}
