#include "IMIEV-CZERO-ION-BATTERY.h"
#include "ESP32CAN.h"
#include "CAN_config.h"

//Code still very WIP
//TODO: Add CMU warning incase we detect a direct connection to the CMUs. It wont be safe to use the battery in this mode
//Map the missing values
//Check scaling of all values
//Generate messages towards BMU to keep it happy?

/* Do not change code below unless you are sure what you are doing */
#define BMU_MAX_SOC 1000  //BMS never goes over this value. We use this info to rescale SOC% sent to inverter
#define BMU_MIN_SOC 0   //BMS never goes below this value. We use this info to rescale SOC% sent to inverter
static uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive 
static uint8_t errorCode = 0; //stores if we have an error code active from battery control logic
static uint8_t BMU_Detected = 0;
static uint8_t CMU_Detected = 0;

static unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was sent
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was sent
static const int interval10 = 10; // interval (ms) at which send CAN Messages
static const int interval100 = 100; // interval (ms) at which send CAN Messages

static int pid_index = 0;
static int cmu_id = 0;
static int voltage_index = 0;
static int temp_index = 0;
static int BMU_SOC = 0;
static double temp1 = 0;
static double temp2 = 0;
static double temp3 = 0;
static double voltage1 = 0;
static double voltage2 = 0;
static double BMU_Current = 0;
static double BMU_PackVoltage = 0;
static double BMU_Power = 0;
static uint16_t cell_voltages[89]; //array with all the cellvoltages //Todo, what is max array size? 80/88 cells?
static uint16_t cell_temperatures[89]; //array with all the celltemperatures //Todo, what is max array size? 80/88cells?


void update_values_imiev_battery()
{ //This function maps all the values fetched via CAN to the correct parameters used for modbus
  bms_status = ACTIVE; //Startout in active mode

  SOC = BMU_SOC; //Todo, scaling?

  battery_voltage = (BMU_PackVoltage*10); //Todo, scaling?

  battery_current = (BMU_Current*10); //Todo, scaling?

  capacity_Wh = BATTERY_WH_MAX; //Hardcoded to header value

  remaining_capacity_Wh = (SOC/100)*capacity_Wh;

  max_target_charge_power; //TODO, map

  max_target_discharge_power; //TODO, map

  stat_batt_power = BMU_Power; //TODO, Scaling?

  temperature_min; //TODO, map

  temperature_max; //TODO, map

  /* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
  if(!CANstillAlive)
  {
    bms_status = FAULT;
    Serial.println("No CAN communication detected for 60s. Shutting down battery control.");
  }
  else
  {
    CANstillAlive--;
  }
	
  if(printValues)
  {  //values heading towards the modbus registers
    Serial.print("BMU SOC: ");
    Serial.println(BMU_SOC);
    Serial.print("BMU Current: ");
    Serial.println(BMU_Current);
    Serial.print("BMU Battery Voltage: ");
    Serial.println(BMU_PackVoltage);
  }
}

void receive_can_imiev_battery(CAN_frame_t rx_frame)
{
  switch (rx_frame.MsgID)
  {
  CANstillAlive = 12; //Todo, move this inside a known message ID to prevent CAN inverter from keeping battery alive detection going
  case 0x374: //BMU message, 10ms - SOC
    BMU_SOC = ((rx_frame.data.u8[1] - 10) / 2);
    break;
  case 0x373: //BMU message, 100ms - Pack Voltage and current
    BMU_Current =  ((((((rx_frame.data.u8[2] * 256.0) + rx_frame.data.u8[3])) - 32768)) * 0.01);
    BMU_PackVoltage = ((rx_frame.data.u8[4] * 256.0 + rx_frame.data.u8[5]) * 0.1);
    BMU_Power = (BMU_Current * BMU_PackVoltage);
    break;
  case 0x6e1: //BMU message, 25ms - Battery temperatures and voltages
  case 0x6e2:
  case 0x6e3:
  case 0x6e4:
    BMU_Detected = 1;
    //Pid index 0-3
    pid_index = (rx_frame.MsgID) - 1761;
    //cmu index 1-12: ignore high order nibble which appears to sometimes contain other status bits
    cmu_id = (rx_frame.data.u8[0] & 0x0f);
    //
    temp1 = rx_frame.data.u8[1] - 50.0;
    temp2 = rx_frame.data.u8[2] - 50.0;
    temp3 = rx_frame.data.u8[3] - 50.0;

    voltage1 = (((rx_frame.data.u8[4] * 256.0 + rx_frame.data.u8[5]) * 0.005) + 2.1);
    voltage2 = (((rx_frame.data.u8[6] * 256.0 + rx_frame.data.u8[7]) * 0.005) + 2.1);

    voltage_index = ((cmu_id - 1) * 8 + (2 * pid_index));
    temp_index = ((cmu_id - 1) * 6 + (2 * pid_index));
    if (cmu_id >= 7)
    {
      voltage_index -= 4;
      temp_index -= 3;
    }
    cell_voltages[voltage_index] = voltage1;
    cell_voltages[voltage_index + 1] = voltage2;

    if (pid_index == 0)
    {
      cell_temperatures[temp_index] = temp2;
      cell_temperatures[temp_index + 1] = temp3;
    }
    else
    {
      cell_temperatures[temp_index] = temp1;
      if (cmu_id != 6 && cmu_id != 12)
      {
        cell_temperatures[temp_index + 1] = temp2;
      }
    }
    break;
  default:
    break;
  }
}

void send_can_imiev_battery()
{
  unsigned long currentMillis = millis();
  // Send 100ms CAN Message
	if (currentMillis - previousMillis100 >= interval100)
	{
		previousMillis100 = currentMillis;
  }
}
