#include "TmStoreTaskBase.h"

#include <fsfw/ipc/CommandMessageIF.h>
#include <fsfw/tasks/TaskFactory.h>
#include <fsfw/timemanager/Stopwatch.h>
#include <fsfw/tmstorage/TmStoreMessage.h>

#include "mission/persistentTmStoreDefs.h"

TmStoreTaskBase::TmStoreTaskBase(object_id_t objectId, StorageManagerIF& ipcStore,
                                 VirtualChannel& channel, SdCardMountedIF& sdcMan)
    : SystemObject(objectId), ipcStore(ipcStore), channel(channel), sdcMan(sdcMan) {}

bool TmStoreTaskBase::handleOneStore(PersistentTmStoreWithTmQueue& store,
                                     DumpContext& dumpContext) {
  ReturnValue_t result;
  bool tmToStoreReceived = false;
  bool tcRequestReceived = false;
  bool dumpsPerformed = false;
  // Store TM persistently
  result = store.handleNextTm();
  if (result == returnvalue::OK) {
    tmToStoreReceived = true;
  }
  // Dump TMs when applicable
  if (store.getState() == PersistentTmStore::State::DUMPING) {
    size_t dumpedLen = 0;
    bool fileHasSwapped;
    if (not channel.isBusy()) {
      tmSinkBusyCd.resetTimer();
      result = store.dumpNextPacket(channel, dumpedLen, fileHasSwapped);
      if ((result == PersistentTmStore::DUMP_DONE or result == returnvalue::OK) and dumpedLen > 0) {
        dumpContext.dumpedBytes += dumpedLen;
        dumpContext.numberOfDumpedPackets += 1;
      }
      if (result == PersistentTmStore::DUMP_DONE) {
        uint32_t startTime;
        uint32_t endTime;
        store.getStartAndEndTimeCurrentOrLastDump(startTime, endTime);
        triggerEvent(dumpContext.eventIfDone, dumpContext.numberOfDumpedPackets,
                     dumpContext.dumpedBytes);
        dumpsPerformed = true;
      } else if (result == returnvalue::OK) {
        dumpsPerformed = true;
      }
    }
    if (cancelDumpCd.hasTimedOut() or tmSinkBusyCd.hasTimedOut()) {
      triggerEvent(persTmStore::DUMP_WAS_CANCELLED, store.getObjectId());
      store.cancelDump();
    }
  } else {
    Command_t execCmd;
    // Handle TC requests, for example deletion or retrieval requests.
    result = store.handleCommandQueue(ipcStore, execCmd);
    if (result == returnvalue::OK) {
      if (execCmd == TmStoreMessage::DOWNLINK_STORE_CONTENT_TIME) {
        cancelDumpCd.resetTimer();
        tmSinkBusyCd.resetTimer();
        dumpContext.reset();
      }
      tcRequestReceived = true;
    }
  }
  if (tcRequestReceived or tmToStoreReceived or dumpsPerformed) {
    return true;
  }
  return false;
}

bool TmStoreTaskBase::cyclicStoreCheck() {
  if (not storesInitialized) {
    storesInitialized = initStoresIfPossible();
    if (not storesInitialized) {
      TaskFactory::delayTask(400);
      return false;
    }
  } else if (sdCardCheckCd.hasTimedOut()) {
    if (not sdcMan.isSdCardUsable(std::nullopt)) {
      // Might be due to imminent shutdown or SD card switch.
      storesInitialized = false;
      TaskFactory::delayTask(100);
      return false;
    }
    sdCardCheckCd.resetTimer();
  }
  return true;
}