#include "EiveSystem.h"

#include <eive/objects.h>
#include <fsfw/events/EventManager.h>
#include <fsfw/ipc/QueueFactory.h>
#include <mission/acs/defs.h>
#include <mission/com/defs.h>
#include <mission/controller/tcsDefs.h>

#include "mission/sysDefs.h"

EiveSystem::EiveSystem(object_id_t setObjectId, uint32_t maxNumberOfSequences,
                       uint32_t maxNumberOfTables)
    : Subsystem(setObjectId, maxNumberOfSequences, maxNumberOfTables) {
  auto mqArgs = MqArgs(SubsystemBase::getObjectId(), static_cast<void*>(this));
  eventQueue =
      QueueFactory::instance()->createMessageQueue(10, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
}

void EiveSystem::announceMode(bool recursive) {
  const char* modeStr = "UNKNOWN";
  switch (mode) {
    case (satsystem::Mode::BOOT): {
      modeStr = "OFF/BOOT";
      break;
    }
    case (satsystem::Mode::SAFE): {
      modeStr = "SAFE";
      break;
    }
    case (satsystem::Mode::PTG_IDLE): {
      modeStr = "POINTING IDLE";
      break;
    }
    case (acs::AcsMode::PTG_INERTIAL): {
      modeStr = "POINTING INERTIAL";
      break;
    }
    case (acs::AcsMode::PTG_TARGET): {
      modeStr = "POINTING TARGET";
      break;
    }
    case (acs::AcsMode::PTG_TARGET_GS): {
      modeStr = "POINTING TARGET GS";
      break;
    }
  }
  sif::info << "EIVE system is now in " << modeStr << " mode" << std::endl;
  return Subsystem::announceMode(recursive);
}

void EiveSystem::performChildOperation() {
  Subsystem::performChildOperation();
  handleEventMessages();
  if (not isInTransition and performSafeRecovery) {
    commandSelfToSafe();
    performSafeRecovery = false;
  }
}

ReturnValue_t EiveSystem::initialize() {
  auto* manager = ObjectManager::instance()->get<EventManagerIF>(objects::EVENT_MANAGER);
  if (manager == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
    sif::error << "AcsSubsystem::initialize: Invalid event manager" << std::endl;
#endif
    return ObjectManagerIF::CHILD_INIT_FAILED;
  }
  ReturnValue_t result = manager->registerListener(eventQueue->getId());
  if (result != returnvalue::OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
    sif::warning << "AcsSubsystem::registerListener: Failed to register as "
                    "listener"
                 << std::endl;
#endif
    return ObjectManagerIF::CHILD_INIT_FAILED;
  }
  manager->subscribeToEvent(eventQueue->getId(),
                            event::getEventId(tcsCtrl::PCDU_SYSTEM_OVERHEATING));
  manager->subscribeToEvent(eventQueue->getId(), event::getEventId(tcsCtrl::OBC_OVERHEATING));

  return Subsystem::initialize();
}

void EiveSystem::handleEventMessages() {
  EventMessage event;
  for (ReturnValue_t status = eventQueue->receiveMessage(&event); status == returnvalue::OK;
       status = eventQueue->receiveMessage(&event)) {
    switch (event.getMessageId()) {
      case EventMessage::EVENT_MESSAGE:
        switch (event.getEvent()) {
          case tcsCtrl::OBC_OVERHEATING:
          case tcsCtrl::PCDU_SYSTEM_OVERHEATING: {
            if (isInTransition) {
              performSafeRecovery = true;
              return;
            }

            commandSelfToSafe();
            break;
          }
        }
        break;
      default:
        sif::debug << "EiveSystem: Did not subscribe to event " << event.getEvent() << std::endl;
        break;
    }
  }
}

void EiveSystem::commandSelfToSafe() { startTransition(satsystem::Mode::SAFE, 0); }