#include "serial_control.h"
#include "charger_gbt.h"
#include "cp.h"
#include "edcan_config.h"
#include <string.h>
#include "board.h"
#include "debug.h"

static void SC_FillGBTMonitorPacket(void);
static void SC_FillCCSMonitorPacket(void);
static void SC_FillInfoPacket(void);

IsolationStatusPacket_t ISO = {
    .isolationResistance = 0xFFFF
};

void SC_CommandHandler(ReceivedCommand_t *cmd) {
    uint8_t response_code = RESP_FAILED;

    if (cmd->command == CMD_ISOLATION_STATUS) {
        if (cmd->argument_length == sizeof(IsolationStatusPacket_t)) {
            memcpy(&ISO, cmd->argument, sizeof(IsolationStatusPacket_t));
            if (g_sc_command_source == SC_SOURCE_UART5) {
                return;
            }
            response_code = RESP_SUCCESS;
        } else {
            response_code = RESP_FAILED;
        }
        SC_SendPacket(NULL, 0, response_code);
        return;
    }

    switch (cmd->command) {

    case CMD_GET_GBT_STATUS:
        SC_FillGBTMonitorPacket();
        SC_SendPacket((const uint8_t *)&gbtMonitorPacket, sizeof(gbtMonitorPacket), CMD_GET_GBT_STATUS);
        return;

    case CMD_GET_CCS_STATUS:
        SC_FillCCSMonitorPacket();
        SC_SendPacket((const uint8_t *)&ccsMonitorPacket, sizeof(ccsMonitorPacket), CMD_GET_CCS_STATUS);
        return;

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

    case CMD_GET_LOG:
        debug_buffer_send();
        return;

    case CMD_GBT_CC_ENABLE:
        if (cmd->argument_length == sizeof(uint8_t)) {
            uint8_t enable = *((uint8_t *)cmd->argument);
            cc_enable = enable ? 1U : 0U;
            response_code = RESP_SUCCESS;
        }
        break;

    case CMD_GBT_STOP:
        if (cmd->argument_length == 0U) {
            CONN[0].connControl = CMD_STOP;
            response_code = RESP_SUCCESS;
        }
        break;

    case CMD_GBT_SET_REQUEST:
        if (cmd->argument_length == sizeof(EvSetLimits_t)) {
            EvSetLimits_t *limits = (EvSetLimits_t *)cmd->argument;
            CONN[0].RequestedVoltage = limits->requestedVoltage;
            CONN[0].RequestedCurrent = limits->requestedCurrent;
            response_code = RESP_SUCCESS;
        }
        break;

    case CMD_GBT_SET_SOC:
        if (cmd->argument_length == sizeof(uint8_t)) {
            CONN[0].SOC = *((uint8_t *)cmd->argument);
            response_code = RESP_SUCCESS;
        }
        break;

    case CMD_GBT_SET_VIN:
        if (cmd->argument_length == 17U) {
            memcpy(GBT_EVInfo.EVIN, cmd->argument, 17U);
            response_code = RESP_SUCCESS;
        }
        break;

    case CMD_CCS_SET_STATE:
        if (cmd->argument_length == sizeof(uint8_t)) {
            cp_state = (CP_State_t)(*((uint8_t *)cmd->argument));
            response_code = RESP_SUCCESS;
        }
        break;

    case CMD_CCS_ENABLE_LOAD:
        if (cmd->argument_length == sizeof(uint8_t)) {
            uint8_t enable = *((uint8_t *)cmd->argument);
            CONN[1].enableLoad = enable ? 1U : 0U;
            CONN[1].ContactorEnabled = CONN[1].enableLoad;
            response_code = RESP_SUCCESS;
        }
        break;

    default:
        response_code = RESP_FAILED;
        break;
    }

    SC_SendPacket(NULL, 0, response_code);
}

static void SC_FillInfoPacket(void) {
    infoPacket.serialNumber = 0;
    infoPacket.boardVersion = 0;
    infoPacket.stationType = 0;
    infoPacket.fw_version_major = FWVER_MAJOR;
    infoPacket.fw_version_minor = FWVER_MINOR;
    infoPacket.fw_version_patch = FWVER_PATCH;
}

static void SC_FillGBTMonitorPacket(void) {
    gbtMonitorPacket.connector_type = 0x01;
    gbtMonitorPacket.requestedVoltage = CONN[0].RequestedVoltage;
    gbtMonitorPacket.requestedCurrent = CONN[0].RequestedCurrent;
    gbtMonitorPacket.measuredVoltageSE = CONN[0].MeasuredVoltageSE;
    gbtMonitorPacket.measuredCurrentSE = CONN[0].MeasuredCurrentSE;
    gbtMonitorPacket.measuredVoltage = CONN[0].MeasuredVoltage;
    gbtMonitorPacket.measuredCurrent = CONN[0].MeasuredCurrent;
    gbtMonitorPacket.cc_enabled = cc_enable;
    gbtMonitorPacket.contactorEnabled = CONN[0].ContactorEnabled;
    gbtMonitorPacket.chargingError = CONN[0].chargingError;
    gbtMonitorPacket.EvseConnected = CONN[0].EvseConnected;
    gbtMonitorPacket.soc = CONN[0].SOC;
    memcpy(gbtMonitorPacket.vin, GBT_EVInfo.EVIN, sizeof(gbtMonitorPacket.vin));
    gbtMonitorPacket.cc_state = CONN_CC_GetState();
    gbtMonitorPacket.logs_available = (debug_buffer_available() > 0U) ? 1U : 0U;
    gbtMonitorPacket.connState = CONN[0].connState;
}

static void SC_FillCCSMonitorPacket(void) {
    CP_Measurement_t cp_meas = CP_GetMeasurement();

    ccsMonitorPacket.connector_type = 0x02;
    ccsMonitorPacket.measuredVoltage = CONN[1].MeasuredVoltage;
    ccsMonitorPacket.measuredCurrent = CONN[1].MeasuredCurrent;
    ccsMonitorPacket.cp_enabled = (cp_state != EV_STATE_A_IDLE) ? 1U : 0U;
    ccsMonitorPacket.contactorEnabled = CONN[1].ContactorEnabled;
    ccsMonitorPacket.chargingError = CONN[1].chargingError;
    ccsMonitorPacket.EvseConnected = CONN[1].EvseConnected;
    ccsMonitorPacket.soc = CONN[1].SOC;
    ccsMonitorPacket.cp_state = (uint8_t)cp_state;
    ccsMonitorPacket.cp_pwm_duty = cp_meas.valid ? cp_meas.duty_percent : 0U;
}

