#ifndef HWDATA_H
#define HWDATA_H

#include <string>
#include <cstdint>
#include <cstring>
#include "esp_err.h"
#include "nvs_flash.h"

#define CURRENT_HWDATA_VERSION 1
#define CURRENT_HWDATA_STRUCT HWData1

#define SSEG_COLOR_COUNT 10
static constexpr const char* SSEG_COLOR_NAMES[SSEG_COLOR_COUNT] = {
    "UNKNOWN",
    "NONE",
    "OTHER",
    "RED",
    "ORANGE",
    "YELLOW",
    "GREEN",
    "BLUE",
    "PURPLE",
    "WHITE"
};
enum class SSegColor : uint8_t {
    UNKNOWN = 0,
    NONE = 1,
    OTHER = 2,
    RED = 3,
    ORANGE = 4,
    YELLOW = 5,
    GREEN = 6,
    BLUE = 7,
    PURPLE = 8,
    WHITE = 9,
};

#define LCD_COLOR_COUNT 8
static constexpr const char* LCD_COLOR_NAMES[LCD_COLOR_COUNT] = {
    "UNKNOWN",
    "NONE",
    "OTHER",
    "BLACK_GREEN",
    "WHITE_BLUE",
    "BLACK_SKY",
    "BLACK_WHITE",
    "WHITE_BLACK"
};
enum class LCDColor : uint8_t {
    UNKNOWN = 0,
    NONE = 1,
    OTHER = 2,
    BLACK_GREEN = 3,
    WHITE_BLUE = 4,
    BLACK_SKY = 5,
    BLACK_WHITE = 6,
    WHITE_BLACK = 7,
};

#define BUTTON_TYPE_COUNT 6
static constexpr const char* BUTTON_TYPE_NAMES[BUTTON_TYPE_COUNT] = {
    "UNKNOWN",
    "NONE",
    "OTHER",
    "WHITE",
    "BROWN",
    "RED"
};
enum class ButtonType : uint8_t {
    UNKNOWN = 0,
    NONE = 1,
    OTHER = 2,
    WHITE = 3,
    BROWN = 4,
    RED = 5,
};

#define TFT_TYPE_COUNT 5
static constexpr const char* TFT_TYPE_NAMES[TFT_TYPE_COUNT] = {
    "UNKNOWN",
    "NONE",
    "OTHER",
    "EAST_RISING",
    "SHENZHEN"
};
enum class TFTType : uint8_t {
    UNKNOWN = 0,
    NONE = 1,
    OTHER = 2,
    EAST_RISING = 3,
    SHENZHEN = 4,
};

#define BAT_TYPE_COUNT 5
static constexpr const char* BAT_TYPE_NAMES[BAT_TYPE_COUNT] = {
    "UNKNOWN",
    "NONE",
    "OTHER",
    "BAT_18650",
    "LIPO"
};
enum class BatType : uint8_t {
    UNKNOWN = 0,
    NONE = 1,
    OTHER = 2,
    BAT_18650 = 3,
    LIPO = 4,
};

#define SHAPE_TYPE_COUNT 11
static constexpr const char* SHAPE_TYPE_NAMES[SHAPE_TYPE_COUNT] = {
    "UNKNOWN",
    "OTHER",
    "CIRCLE",
    "SQUARE",
    "TRIANGLE",
    "X",
    "STAR",
    "SPADE",
    "DIAMOND",
    "CLUB",
    "HEART"
};
enum class ShapeType : uint8_t {
    UNKNOWN = 0,
    OTHER = 1,
    CIRCLE = 2,
    SQUARE = 3,
    TRIANGLE = 4,
    X = 5,
    STAR = 6,
    SPADE = 7,
    DIAMOND = 8,
    CLUB = 9,
    HEART = 10,
};



/// @brief Version 1 of HWData, kept constant for migrations
struct HWData1 {
    std::string serial_num;
    uint8_t rev_ctrl_maj;
    uint8_t rev_ctrl_min;
    uint8_t rev_exp_maj;
    uint8_t rev_exp_min;
    uint8_t rev_ft_maj;
    uint8_t rev_ft_min;
    uint8_t rev_fb_maj;
    uint8_t rev_fb_min;

    SSegColor sseg_color_t;
    SSegColor sseg_color_b;
    LCDColor lcd_color;
    uint8_t switch_pos;
    ButtonType button_type;
    TFTType tft_type;
    BatType bat_type;
    uint16_t bat_cap;

    ShapeType shape1;
    ShapeType shape2;
    ShapeType shape3;
    ShapeType shape4;

    bool has_speaker;
    bool has_mic;
    bool has_ir;
    bool has_rfid;
    bool has_fp;
    bool has_fp_hall;
    bool has_close_hall;

    HWData1();

    esp_err_t save(nvs_handle_t handle) const;
    void load(nvs_handle_t handle);

    // Add migration method as necessary
};

/// @brief The current version of HWData, to be stored
struct HWData {
    /// @brief `true` if there is some issue in loading, and we are doing a "best effort" to be compatible
    /// We should make no writes to NVS if this is `true`.
    volatile bool compat_mode;
    HWData1 inner;

    HWData();
    HWData(HWData1 data, bool compat_mode);

    esp_err_t save(nvs_handle_t handle, bool force = false);
    static HWData load(nvs_handle_t handle);
};

void hardware_config();

#endif /* HWDATA_H */
