#pragma once

#include "helpers/AbstractBridge.h"
#include "helpers/CommonCLI.h"
#include "helpers/SimpleMeshTables.h"

#include <RTClib.h>

/**
 * @brief Base class implementing common bridge functionality
 *
 * This class provides common functionality used by different bridge implementations
 * like packet tracking, checksum calculation, timestamping, and duplicate detection.
 *
 * Features:
 * - Fletcher-16 checksum calculation for data integrity
 * - Packet duplicate detection using SimpleMeshTables
 * - Common timestamp formatting for debug logging
 * - Shared packet management and queuing logic
 */
class BridgeBase : public AbstractBridge {
public:
  virtual ~BridgeBase() = default;

  /**
   * @brief Gets the current state of the bridge.
   *
   * @return true if the bridge is initialized and running, false otherwise.
   */
  bool isRunning() const override;

  /**
   * @brief Common magic number used by all bridge implementations for packet identification
   *
   * This magic number is placed at the beginning of bridge packets to identify
   * them as mesh bridge packets and provide frame synchronization.
   */
  static constexpr uint16_t BRIDGE_PACKET_MAGIC = 0xC03E;

  /**
   * @brief Common field sizes used by bridge implementations
   *
   * These constants define the size of common packet fields used across bridges.
   * BRIDGE_MAGIC_SIZE is used by all bridges for packet identification.
   * BRIDGE_LENGTH_SIZE is used by bridges that need explicit length fields (like RS232).
   * BRIDGE_CHECKSUM_SIZE is used by all bridges for Fletcher-16 checksums.
   */
  static constexpr uint16_t BRIDGE_MAGIC_SIZE = sizeof(BRIDGE_PACKET_MAGIC);
  static constexpr uint16_t BRIDGE_LENGTH_SIZE = sizeof(uint16_t);
  static constexpr uint16_t BRIDGE_CHECKSUM_SIZE = sizeof(uint16_t);

protected:
  /** Tracks bridge state */
  bool _initialized = false;

  /** Packet manager for allocating and queuing mesh packets */
  mesh::PacketManager *_mgr;

  /** RTC clock for timestamping debug messages */
  mesh::RTCClock *_rtc;

  /** Node preferences for configuration settings */
  NodePrefs *_prefs;

  /** Tracks seen packets to prevent loops in broadcast communications */
  SimpleMeshTables _seen_packets;

  /**
   * @brief Constructs a BridgeBase instance
   *
   * @param prefs Node preferences for configuration settings
   * @param mgr PacketManager for allocating and queuing packets
   * @param rtc RTCClock for timestamping debug messages
   */
  BridgeBase(NodePrefs *prefs, mesh::PacketManager *mgr, mesh::RTCClock *rtc)
      : _prefs(prefs), _mgr(mgr), _rtc(rtc) {}

  /**
   * @brief Gets formatted date/time string for logging
   *
   * Format: "HH:MM:SS - DD/MM/YYYY U"
   *
   * @return Formatted date/time string
   */
  const char *getLogDateTime();

  /**
   * @brief Calculate Fletcher-16 checksum
   *
   * Based on: https://en.wikipedia.org/wiki/Fletcher%27s_checksum
   * Used to verify data integrity of received packets
   *
   * @param data Pointer to data to calculate checksum for
   * @param len Length of data in bytes
   * @return Calculated Fletcher-16 checksum
   */
  static uint16_t fletcher16(const uint8_t *data, size_t len);

  /**
   * @brief Validate received checksum against calculated checksum
   *
   * @param data Pointer to data to validate
   * @param len Length of data in bytes
   * @param received_checksum Checksum received with data
   * @return true if checksum is valid, false otherwise
   */
  bool validateChecksum(const uint8_t *data, size_t len, uint16_t received_checksum);

  /**
   * @brief Common packet handling for received packets
   *
   * Implements the standard pattern used by all bridges:
   * - Check if packet was seen before using _seen_packets.hasSeen()
   * - Queue packet for mesh processing if not seen before
   * - Free packet if already seen to prevent duplicates
   *
   * @param packet The received mesh packet
   */
  void handleReceivedPacket(mesh::Packet *packet);
};
