#pragma once

#include "core/eventBus/eventBus.h"
#include "core/track/track.h"
#include "playerDefs.h"

#include <atomic>
#include <filesystem>
#include <mutex>

namespace player
{
//--------------------------------------------------------------
class Player : public sdi_toolBox::desktop::eventBus::Node
{
  // using DefaultMessageType = std::shared_ptr<sdi_toolBox::desktop::eventBus::Message>;
  static constexpr auto WindowDuration = track::Seconds(1.5);

  public:
  Player()                                 = delete;      // Default constructor
  virtual ~Player()                        = default;     // Default destructor
  Player(const Player &obj)                = delete;      // Copy constructor
  Player(Player &&obj) noexcept            = delete;      // Move constructor
  Player &operator=(const Player &obj)     = delete;      // Copy assignment operator
  Player &operator=(Player &&obj) noexcept = delete;      // Move assignment operator

  explicit Player(sdi_toolBox::desktop::eventBus::Bus &hBus);     // Constructor

  void                      update();                   // Update the player state based on the current state and time
  const track::ActiveNotes &getActiveNotes() const;     // Get the currently active notes

  // Track management
  void loadFile(const std::filesystem::path &filePath);     // Load a MIDI file from disk
  void closeFile();                                         // Close the currently loaded MIDI file

  // --- Notes access ---
  track::TrackLockProxy getNotes() const;     // Get a lock proxy to access the notes safely without copying the data

  protected:
  struct
  {
    mutable std::mutex mtx;
    track::Track       track;     // Track instance to be played
  } m_data;

  struct PlaybackClock
  {
    std::atomic<State> state           = State::Stopped;
    TimePoint          startTime       = TimePoint();
    Seconds            pauseOffset     = Seconds(0);
    Seconds            currentPosition = Seconds(0);

    void reset();            // Reset the playback clock to its initial state (stopped, zero position)
    void startNew();         // Start a new playback session, resetting the clock and position
    void startPlaying();     // Start playing from the current position
    void pause();            // Pause the playback clock and store the current position
    void resume();           // Resume the playback clock from the paused position
  } m_playback;

  track::ActiveNotes m_activeNotes;     // Currently active notes

  struct EventProcessing
  {
    EventProcessing() = delete;                               // Default constructor
    explicit EventProcessing(Player &pPlayer);                // Constructor
    ~EventProcessing();                                       // Default destructor
    void start();                                             // Start the event processing thread
    void stop();                                              // Stop the event processing thread
    void process(const std::stop_token &stopToken) const;     // Event processing loop

    std::jthread thread;
    Player      &player;
  } m_eventProcessing;

  private:
  void on_remoteLoadFile(const std::shared_ptr<GenericMessageEvent> &message);     // Handle the "remote.loadFile" message
  void on_remoteSetState(const std::shared_ptr<GenericMessageEvent> &message);     // Handle the "remote.setState" message
};
//--------------------------------------------------------------
}     // namespace player
