#ifndef CLI_PROTOCOL_H
#define CLI_PROTOCOL_H

#include "cli_protocol_cfg.h"
#include "l_macro_types.h"
#include <stdbool.h>

//************************************ Константы протокола *************************************************
#define CLI_BROADCAST_ID            0xFFU    // Широковещательный адрес (команды для всех плат без ответа)

//************************************ Коды команд (по протоколу 1.1) *************************************
typedef enum {
    CLI_CMD_OPEN        = 0x00U,    // T00 - открыть соединение (опционально с паролем)
    CLI_CMD_CLOSE       = 0x01U,    // T01 - закрыть соединение
    CLI_CMD_PING        = 0x02U,    // T02 - проверка соединения (ping) – эхо переданных данных
    CLI_CMD_GET_INFO    = 0x0AU,    // T0A - получить информацию об устройстве (имя, серийный, версия)
    CLI_CMD_READ_MEM    = 0x14U,    // T14 - чтение памяти (адрес 4 байта + размер 1 байт)
    CLI_CMD_WRITE_MEM   = 0x15U,    // T15 - запись памяти (адрес 4 байта + данные, только SRAM)
} cli_cmd_t;

//************************************ Коды ошибок (только 00-03 по протоколу) ****************************
typedef enum {
    CLI_ERR_NONE         = 0x00U,   // Нет ошибки
    CLI_ERR_UNKNOWN_CMD  = 0x01U,   // Неизвестная команда
    CLI_ERR_INVALID_ARG  = 0x02U,   // Неверный формат или значение аргумента
    CLI_ERR_INTERNAL     = 0x03U,   // Внутренняя ошибка устройства
} cli_error_t;

//************************************ Информация об устройстве **********************************************
//! @brief Структура с информацией об устройстве, возвращаемая командой T0A
typedef struct {
    char name[32];      // Имя устройства (ASCII, до 31 символа + \\0)
    char serial[16];    // Серийный номер (ASCII, до 15 символов + \\0)
    char version[16];   // Версия ПО (ASCII, до 15 символов + \\0)
    u8  board_id;       // Уникальный идентификатор платы (0–254)
} cli_device_info_t;

//************************************ Тип обработчика команды **********************************************
//! @brief Прототип функции-обработчика команды
//! @param data Указатель на сырые данные команды (после board_id)
//! @param len  Длина данных в байтах
typedef void (*cli_cmd_handler_t)(const u8* data, u8 len);

//************************************ Структура регистрируемой команды **************************************


// TODO - че, прям реально от 0x00–0xFF, а как же встроенные команды?

//! @brief Структура для регистрации пользовательской команды
typedef struct {
    u8 code;                    // Код команды (0x00–0xFF)
    cli_cmd_handler_t handler;  // Указатель на функцию-обработчик
} cli_command_t;

//************************************ Публичные функции ****************************************************

//---------------------------------------------------------------------
//! @brief Инициализация протокола CLI
//! @return ERR_OK при успехе, иначе код ошибки
fun_res_t cli_protocol_init(void);

//---------------------------------------------------------------------
//! @brief Деинициализация протокола CLI
//! @return ERR_OK при успехе, иначе код ошибки
fun_res_t cli_protocol_deinit(void);

//---------------------------------------------------------------------
//! @brief Основной цикл обработки (вызывать в главном цикле программы)
void cli_protocol_process(void);


// TODO - сделать с параметром - блок\ не блок
//---------------------------------------------------------------------
//! @brief Отправка строки через UART (с ожиданием завершения передачи)
//! @param str Указатель на нуль-терминированную строку
void cli_send_string(const char* str);





//---------------------------------------------------------------------
//! @brief Установка информации об устройстве
//! @param name      Имя устройства (до 31 символа)
//! @param serial    Серийный номер (до 15 символов)
//! @param ver       Версия ПО (до 15 символов)
//! @param board_id  Идентификатор платы (0–254)
//! @return ERR_OK при успехе
fun_res_t cli_protocol_set_device_info(const char* name, const char* serial, const char* ver, u8 board_id);


// todo - а зачем
//---------------------------------------------------------------------
//! @brief Установка board_id устройства
//! @param board_id Идентификатор платы (0–254)
//! @return ERR_OK при успехе
fun_res_t cli_protocol_set_board_id(u8 board_id);


// todo - а зачем
//---------------------------------------------------------------------
//! @brief Получение текущего board_id устройства
//! @return Идентификатор платы
u8 cli_protocol_get_board_id(void);





//---------------------------------------------------------------------
//! @brief Установка пароля для открытия соединения
//! @param pass Указатель на массив байт пароля (до 15 байт)
//! @param len  Длина пароля в байтах
void cli_protocol_set_password(const u8* pass, u8 len);


// todo - а зачем
//---------------------------------------------------------------------
//! @brief Проверка пароля
//! @param pass Указатель на массив байт пароля
//! @param len  Длина пароля в байтах
//! @return true – пароль верен, false – неверен
bool cli_protocol_verify_password(const u8* pass, u8 len);


// todo - а где реализация: cli_protocol_reset_block

//---------------------------------------------------------------------
//! @brief Сброс блокировки после превышения попыток ввода пароля
void cli_protocol_reset_block(void);

//---------------------------------------------------------------------
//! @brief Регистрация новой команды
//! @param cmd Указатель на структуру с кодом и обработчиком
//! @return ERR_OK при успехе, ERR_INVALID_ARGUMENT – неверные параметры,
//!         ERR_RUNTIME_ERROR – команда уже зарегистрирована
fun_res_t cli_register_command(const cli_command_t* cmd);


#endif