#include "WatchdogHandler.h"

#include <fcntl.h>
#include <unistd.h>

#include <cerrno>
#include <cstring>
#include <filesystem>

#include "fsfw/serviceinterface.h"
#include "watchdog/definitions.h"

WatchdogHandler::WatchdogHandler() {}

void WatchdogHandler::periodicOperation() {
  if (watchdogFifoFd != 0) {
    if (watchdogFifoFd == RETRY_FIFO_OPEN) {
      // Open FIFO write only and non-blocking
      watchdogFifoFd = open(watchdog::FIFO_NAME.c_str(), O_WRONLY | O_NONBLOCK);
      if (watchdogFifoFd < 0) {
        if (errno == ENXIO) {
          watchdogFifoFd = RETRY_FIFO_OPEN;
          // No printout for now, would be spam
          return;
        } else {
          sif::error << "Opening pipe " << watchdog::FIFO_NAME << " write-only failed with "
                     << errno << ": " << strerror(errno) << std::endl;
          return;
        }
      }
      sif::info << "Opened " << watchdog::FIFO_NAME << " successfully" << std::endl;
      performStartHandling();
    } else if (watchdogFifoFd > 0) {
      // Write to OBSW watchdog FIFO here
      const char writeChar = watchdog::first::IDLE_CHAR;
      ssize_t writtenBytes = write(watchdogFifoFd, &writeChar, 1);
      if (writtenBytes < 0) {
        sif::error << "Errors writing to watchdog FIFO, code " << errno << ": " << strerror(errno)
                   << std::endl;
      }
    }
  }
}

ReturnValue_t WatchdogHandler::initialize(bool enableWatchdogFunction) {
  using namespace std::filesystem;
  this->enableWatchFunction = enableWatchdogFunction;
  std::error_code e;
  if (not std::filesystem::exists(watchdog::FIFO_NAME, e)) {
    // Still return returnvalue::OK for now
    sif::info << "Watchdog FIFO " << watchdog::FIFO_NAME << " does not exist, can't initiate"
              << " watchdog" << std::endl;
    return returnvalue::OK;
  }
  // Open FIFO write only and non-blocking to prevent SW from killing itself.
  watchdogFifoFd = open(watchdog::FIFO_NAME.c_str(), O_WRONLY | O_NONBLOCK);
  if (watchdogFifoFd < 0) {
    if (errno == ENXIO) {
      watchdogFifoFd = RETRY_FIFO_OPEN;
      sif::info << "eive-watchdog not running. FIFO can not be opened" << std::endl;
    } else {
      sif::error << "Opening pipe " << watchdog::FIFO_NAME << " write-only failed with " << errno
                 << ": " << strerror(errno) << std::endl;
      return returnvalue::FAILED;
    }
  }
  return performStartHandling();
}

ReturnValue_t WatchdogHandler::performStartHandling() {
  char startBuf[2];
  ssize_t writeLen = 1;
  startBuf[0] = watchdog::first::START_CHAR;
  if (enableWatchFunction) {
    writeLen += 1;
    startBuf[1] = watchdog::second::WATCH_FLAG;
  }
  ssize_t writtenBytes = write(watchdogFifoFd, &startBuf, writeLen);
  if (writtenBytes < 0) {
    sif::error << "WatchdogHandler: Errors writing to watchdog FIFO, code " << errno << ": "
               << strerror(errno) << std::endl;
    return returnvalue::FAILED;
  } else if (writtenBytes != writeLen) {
    sif::warning << "WatchdogHandler: Not all bytes were written, possible error" << std::endl;
  }
  return returnvalue::OK;
}