#include "serial_control.h"

#include "board.h"
#include "charger_control.h"
#include "debug.h"
#include "fire_alarm.h"
#include "psu_control.h"
#include "usart.h"
#include <string.h>

extern volatile SC_Source_t g_sc_command_source;
static void monitoring_data_callback(void);

IsolationStatusPacket_t ISO = {
    .isolationResistance = 0xFFFF
};


uint8_t config_initialized = 0;
ConfigBlock_t config = {
    .location = "RUS",
    .chargerNumber = 00001,
    .unixTime = 1721651966,
};

// Единая функция-обработчик всех команд со switch-case
void SC_CommandHandler(ReceivedCommand_t* cmd) {
    
    uint8_t response_code = RESP_FAILED;

    if (FireAlarm_IsBlockingCommand(cmd->command)) {
        SC_SendPacket(NULL, 0, RESP_FAILED);
        return;
    }

    switch (cmd->command) {
        // Команды БЕЗ аргументов
        case CMD_GET_STATUS:
            // Логика получения информации
            monitoring_data_callback();

            // Отправляем с нормальным приоритетом
            SC_SendPacket((uint8_t*)&statusPacket, sizeof(statusPacket), CMD_GET_STATUS);
            return; // Специальный ответ уже отправлен

        case CMD_GET_INFO:
            SC_SendPacket((uint8_t*)&infoPacket, sizeof(infoPacket), CMD_GET_INFO);
            return;

        case CMD_GET_LOG:
            debug_buffer_send();
            return; // Ответ формируется внутри debug_buffer_send
            
        // Команды С аргументами

        case CMD_SET_CONFIG:
            if (cmd->argument_length == sizeof(ConfigBlock_t)) {
                memcpy(&config, cmd->argument, sizeof(ConfigBlock_t));
                config_initialized = 1;
                log_printf(LOG_INFO, "Set Config: %s %d\n", config.location, config.chargerNumber);
                response_code = RESP_SUCCESS;
                break;
            }
            response_code = RESP_FAILED;
            break;
        case CMD_SET_POWER_LIMIT:
            if (cmd->argument_length == 1) {
                PSU0.power_limit = ((uint8_t*)cmd->argument)[0] * 1000;
                log_printf(LOG_INFO, "Power limit: %d\n", PSU0.power_limit);
                //CONN.connState = (((uint8_t*)cmd->argument)[0])/4;
                response_code = RESP_SUCCESS;
                break;
            }
            response_code = RESP_FAILED;
            break;
        case CMD_CHARGE_PERMIT:
            if (cmd->argument_length == 1) {
                CONN.connControl = ((uint8_t*)cmd->argument)[0];
                log_printf(LOG_INFO, "Charge permit: %d\n", CONN.connControl);
                response_code = RESP_SUCCESS;
                break;
            }
            response_code = RESP_FAILED;
            break;

        case CMD_TEST_PSU:
            // if (cmd->argument_length == sizeof(PSU_TestMode_t)) {
            //     memcpy(&PSU_TestMode, cmd->argument, sizeof(PSU_TestMode_t));
            //     log_printf(LOG_INFO, "Test PSU: %d %d %d\n", PSU_TestMode.enable, PSU_TestMode.voltage, PSU_TestMode.current);
            //     response_code = RESP_SUCCESS;
            //     break;
            // }
            response_code = RESP_FAILED;
            break;
        case CMD_FIRE_ALARM:
            FireAlarm_Activate();
            response_code = RESP_SUCCESS;
            break;

        case CMD_DEVICE_RESET:
            // 2. Отправляем SUCCESS (хост может успеть получить его перед ребутом)
            SC_SendPacket(NULL, 0, RESP_SUCCESS);

            while(huart2.gState == HAL_UART_STATE_BUSY_TX); // Ожидание завершения передачи

            HAL_Delay(10);
            // 3. Выполняем программный сброс
            NVIC_SystemReset();
            return; // Сюда код уже не дойдет, но для компилятора нxужно

        case CMD_ISOLATION_STATUS:
            if (cmd->argument_length == sizeof(IsolationStatusPacket_t)) {
                memcpy(&ISO, cmd->argument, sizeof(IsolationStatusPacket_t));
                // Для однонаправленного UART5 ответ не нужен
                if (g_sc_command_source == SC_SOURCE_UART5) {
                    return;
                }
                response_code = RESP_SUCCESS;
                break;
            }
            response_code = RESP_FAILED;
            break;

        default:
            // Неизвестная команда
            response_code = RESP_FAILED;
            break;
    }

    // Отправляем финальный ответ (для команд без собственного ответа)
    SC_SendPacket(NULL, 0, response_code);
}


// Колбэк для заполнения данных мониторинга
static void monitoring_data_callback(void) {

    // Информация о зарядной сессии
	statusPacket.SOC = CONN.SOC;
	statusPacket.Energy = CONN.Energy;
	statusPacket.RequestedVoltage = CONN.RequestedVoltage;
	statusPacket.RequestedCurrent = CONN.WantedCurrent;
	statusPacket.MeasuredVoltage = CONN.MeasuredVoltage;
	statusPacket.MeasuredCurrent = CONN.MeasuredCurrent;
	statusPacket.outputEnabled = CONN.outputEnabled;
	statusPacket.chargingError = CONN.chargingError;
    statusPacket.connState = CONN.connState;
    statusPacket.chargingElapsedTimeMin = 0;
    statusPacket.chargingElapsedTimeSec = 0;
    statusPacket.estimatedRemainingChargingTime = 0;

    // состояние зарядной станции
    statusPacket.relayAC = RELAY_Read(RELAY_AC);
    statusPacket.relayDC = RELAY_Read(RELAY_DC);
    statusPacket.relayAUX = RELAY_Read(RELAY_AUX0);
    statusPacket.lockState = 0;
    statusPacket.stopButton = !IN_ReadInput(IN_ESTOP);
    statusPacket.logAvailable = (debug_buffer_available()>0)?1:0;
    statusPacket.evInfoAvailable = 0;
    statusPacket.psuOnline = PSU0.online;

    statusPacket.tempConnector0 = CONN_ReadTemp(0); // температура коннектора
    statusPacket.tempConnector1 = CONN_ReadTemp(1);
    statusPacket.tempAmbient = PSU0.tempAmbient; // температура окружающего воздуха
    statusPacket.tempBatteryMax = 0;
    statusPacket.tempBatteryMin = 0;

    statusPacket.highestVoltageOfBatteryCell = 0;
    statusPacket.batteryStatus = 0;

    statusPacket.phaseVoltageAB = PSU_06.VAB;
    statusPacket.phaseVoltageBC = PSU_06.VBC;
    statusPacket.phaseVoltageCA = PSU_06.VCA;

    // GBT TODO
    memset(statusPacket.VIN, 0, sizeof(statusPacket.VIN));

    // GBT TODO
    statusPacket.batteryType = 0;
	statusPacket.batteryCapacity = 0;
	statusPacket.batteryVoltage = 0;
	memset(statusPacket.batteryVendor, 0, sizeof(statusPacket.batteryVendor));
	statusPacket.batterySN = 0;
    statusPacket.batteryManuD = 0;
	statusPacket.batteryManuM = 0;
	statusPacket.batteryManuY = 0;
	statusPacket.batteryCycleCount = 0;
	statusPacket.ownAuto = 0;
    memset(statusPacket.EV_SW_VER, 0, sizeof(statusPacket.EV_SW_VER));

    statusPacket.testMode = 0;
    statusPacket.testVoltage = 0;
    statusPacket.testCurrent = 0;

    // Информация о тачке

	// --- Информация об EV (из команды info2) ---
	// memcpy(statusPacket.version, GBT_EVInfo.version, sizeof(statusPacket.version));
	

	// --- Состояние Hardware и GBT (различные команды) ---
	//statusPacket.lockState = GBT_LockGetState(); // Из команды lock_state
	//statusPacket.ccState = CONN_CC_GetState();   // Из команды cc_state
	//statusPacket.ccAdc = CONN_CC_GetAdc();       // Из команды adc

	// --- Поля, требующие внимания (неявные геттеры) ---

	// 1. Состояние соединения (ConnState)
	// В debug.c есть CONN_SetState, предполагаем наличие CONN_GetState()
	// Если такой функции нет, закомментируйте следующую строку:
	// statusPacket.connState = CONN_GetState();


}

