#ifndef MISSION_TMTC_TMSTOREBACKEND_H_
#define MISSION_TMTC_TMSTOREBACKEND_H_

#include <fsfw/objectmanager/SystemObject.h>
#include <fsfw/timemanager/CdsShortTimeStamper.h>
#include <fsfw/tmstorage/TmStoreFrontendSimpleIF.h>
#include <fsfw/tmtcpacket/pus/tm/PusTmReader.h>
#include <fsfw/tmtcservices/AcceptsTelemetryIF.h>
#include <mission/memory/SdCardMountedIF.h>

#include <filesystem>

#include "TmFunnelBase.h"
#include "eive/eventSubsystemIds.h"

struct PacketFilter {
  std::optional<std::vector<uint16_t>> apid;
  std::optional<std::vector<uint8_t>> services;
  std::optional<std::vector<std::pair<uint8_t, uint8_t>>> serviceSubservices;
};

enum class RolloverInterval { MINUTELY, HOURLY, DAILY };

class PersistentTmStore : public TmStoreFrontendSimpleIF, public SystemObject {
 public:
  static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PERSISTENT_TM_STORE;

  //! [EXPORT] : [COMMENT]
  //! P1: Result code of TM packet parser.
  //! P2: Timestamp of possibly corrupt file as a unix timestamp.
  static constexpr Event POSSIBLE_FILE_CORRUPTION =
      event::makeEvent(SUBSYSTEM_ID, 0, severity::LOW);
  PersistentTmStore(object_id_t objectId, const char* baseDir, std::string baseName,
                    RolloverInterval intervalUnit, uint32_t intervalCount,
                    StorageManagerIF& tmStore, SdCardMountedIF& sdcMan);

  ReturnValue_t initializeTmStore();
  ReturnValue_t handleCommandQueue(StorageManagerIF& ipcStore, TmFunnelBase& tmFunnel);

  void addApid(uint16_t apid);
  void addService(uint8_t service);
  void addServiceSubservice(uint8_t service, uint8_t subservice);

  void deleteUpTo(uint32_t unixSeconds);
  void dumpFrom(uint32_t fromUnixSeconds, TmFunnelBase& tmFunnel);
  void dumpFromUpTo(uint32_t fromUnixSeconds, uint32_t upToUnixSeconds, TmFunnelBase& tmFunnel);

  ReturnValue_t passPacket(PusTmReader& reader);

 private:
  static constexpr uint8_t MAX_FILES_IN_ONE_SECOND = 10;
  static constexpr size_t MAX_FILESIZE = 8192;
  // ISO8601 timestamp.
  static constexpr char FILE_DATE_FORMAT[] = "%FT%H%M%SZ";

  MessageQueueIF* tcQueue;
  PacketFilter filter;
  CdsShortTimeStamper timeReader;
  bool baseDirUninitialized = true;
  const char* baseDir;
  std::string baseName;
  uint8_t currentSameSecNumber = 0;
  std::filesystem::path basePath;
  uint32_t rolloverDiffSeconds = 0;
  std::array<uint8_t, MAX_FILESIZE> fileBuf{};
  timeval currentTv;
  timeval activeFileTv{};
  std::optional<std::filesystem::path> activeFile;
  SdCardMountedIF& sdcMan;
  StorageManagerIF& tmStore;

  /**
   * To get the queue where commands shall be sent.
   * @return  Id of command queue.
   */
  [[nodiscard]] MessageQueueId_t getCommandQueue() const override;

  void calcDiffSeconds(RolloverInterval intervalUnit, uint32_t intervalCount);
  ReturnValue_t createMostRecentFile(std::optional<uint8_t> suffix);
  static ReturnValue_t pathToTm(const std::filesystem::path& path, struct tm& time);
  void fileToPackets(const std::filesystem::path& path, uint32_t unixStamp, TmFunnelBase& funnel);
  bool updateBaseDir();
  ReturnValue_t assignAndOrCreateMostRecentFile();
  ReturnValue_t storePacket(PusTmReader& reader);
};

#endif /* MISSION_TMTC_TMSTOREBACKEND_H_ */