#pragma once

#include <chrono>
#include <cstdint>
#include <filesystem>
#include <mutex>
#include <span>
#include <vector>

//--------------------------------------------------------------
class ITrack
{
  public:
  using Timestamp = std::chrono::milliseconds;

  enum class TrackType : uint8_t
  {
    Unknown   = 0,
    LeftHand  = 1,
    RightHand = 2
  };

  struct NoteEvent
  {
    Timestamp startTimestamp;     // The timestamp when the note event starts
    Timestamp endTimestamp;       // The timestamp when the note event ends
    TrackType trackType;          // The type of the track (LeftHand, RightHand, ...)
    int       pitch;              // The MIDI note number (0-127)
    int       velocity;           // The velocity of the note (0-127)
    bool      noteOn;             // True if the event is a Note On event, false otherwise (Note Off)
  };

  struct TrackWindow
  {
    std::vector<NoteEvent>     activeNotes;       // The notes that are currently active (long notes)
    std::span<const NoteEvent> upcomingNotes;     // The notes that are about to start

    std::unique_lock<std::mutex> lock;     // Lock to protect access to the data structures
  };

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

  // --- File management ---
  virtual void                    loadFromFile(const std::filesystem::path &filePath) = 0;     // Load a MIDI file from disk
  virtual void                    loadFromMemory(std::span<uint8_t> midiBytes)        = 0;     // Load a MIDI file from memory
  virtual void                    clear()                                             = 0;     // Clear the track data
  [[nodiscard]] virtual bool      isLoaded() const                                    = 0;     // Check if a MIDI file is loaded
  [[nodiscard]] virtual Timestamp getDuration() const                                 = 0;     // Get the duration of the track in milliseconds

  virtual void debug() = 0;     // Debug function to print the track data

  // --- Rendering ---
  [[nodiscard]] virtual TrackWindow getTrackWindow(Timestamp startTime, Timestamp endTime) const = 0;     // Get notes in a given time window
};
//--------------------------------------------------------------
