#ifndef ODIN_NODEJS_ODINROOM_H
#define ODIN_NODEJS_ODINROOM_H

#include <napi.h>
#include <odin.h>
// Forward declaration instead of including odin_crypto.h
struct OdinCipher;
#include "utilities.h"
#include <map>
#include <thread>
#include <mutex>
#include <atomic>

class OdinRoomWrapper : public Napi::ObjectWrap<OdinRoomWrapper> {

public:
    OdinRoomWrapper(const Napi::CallbackInfo& info);
    static Napi::FunctionReference *New;
    static Napi::Object Init(Napi::Env env, Napi::Object exports);
    static Napi::Value CreateNewItem(const Napi::CallbackInfo& info);
    void Finalize(Napi::Env env) override;
    
    // Callbacks for Connection Pool
    static void OnDatagram(uint64_t room_ref, uint16_t media_id, const uint8_t *bytes, uint32_t bytes_length, void *user_data);
    static void OnRPC(uint64_t room_ref, const uint8_t *bytes, uint32_t bytes_length, void *user_data);

    struct OdinRoom* GetRoom() const { return _room; }
    static Napi::FunctionReference *constructor;
    static Napi::Object NewInstance(Napi::Value arg);
    
    // SDK lifecycle management - reference counting for proper initialization/shutdown
    static void IncrementRoomCount();
    static void DecrementRoomCount();
    
    // Internal handler called by static callbacks
    void HandleDatagramInternal(uint16_t media_id, const uint8_t *bytes, uint32_t bytes_length);
    void HandleRPCInternal(const uint8_t *bytes, uint32_t bytes_length);

    struct OdinRoom* _room; 
    
private:
    struct OdinCipher* _cipher;
    
    // Static connection pool for all rooms
    static struct OdinConnectionPool* _pool;
    static std::map<uint64_t, OdinRoomWrapper*> _roomsMap;
    static std::mutex _roomsMapMutex;

    static struct OdinConnectionPool* GetConnectionPool();

    std::string _token;
    
    std::map<uint16_t, struct OdinDecoder*> _decoders;
    std::mutex _decodersMutex;
    
    // Mapping from media_id to peer_id (populated from JavaScript via MediaStarted events)
    std::map<uint16_t, uint64_t> _mediaToPeer;
    std::mutex _mediaToPeerMutex;
    
    // Own peer ID (set from JavaScript after joining)
    uint64_t _ownPeerId;
    
    // Position coordinates (x, y, z) for spatial audio and server-side culling
    // These are stored and used during odin_room_create_ex call in Join()
    float _position[3];
    
    // Position scale factor - divides position coordinates to normalize to unit circle
    float _positionScale;

    std::thread _nativeThread;
    std::atomic<bool> _started;
    
    // Counter for pending NonBlockingCall callbacks
    // Incremented before NonBlockingCall, decremented when callback completes
    // Used to ensure all callbacks finish before releasing ThreadSafeFunctions
    std::atomic<int> _pendingCallbacks;
    
    bool _joined;
    
    float _audioSamplesBuffer[1920]; 

    std::map<std::string, Napi::ThreadSafeFunction> _eventListeners;
    Napi::ThreadSafeFunction _eventListener; // Restored
    Napi::ThreadSafeFunction _audioDataReceivedEventListener;

    void Close(const Napi::CallbackInfo& info);
    void Join(const Napi::CallbackInfo& info);
    void UpdatePeerUserData(const Napi::CallbackInfo &info);
    void SendMessage(const Napi::CallbackInfo &info); 
    void SendRpc(const Napi::CallbackInfo &info); 
    
    void SetEventListener(const Napi::CallbackInfo &info);
    void AddEventListener(const Napi::CallbackInfo &info);
    void RemoveEventListener(const Napi::CallbackInfo &info);
    Napi::Value GetOwnPeerId(const Napi::CallbackInfo &info);
    Napi::Value RoomId(const Napi::CallbackInfo &info);
    void SetCipher(const Napi::CallbackInfo &info);
    
    // Methods for JavaScript to register media-to-peer mapping
    void RegisterMediaPeer(const Napi::CallbackInfo &info);
    void UnregisterMedia(const Napi::CallbackInfo &info);
    void SetOwnPeerId(const Napi::CallbackInfo &info);
    
    void HandleAudioData(); 
    void UpdatePosition(const Napi::CallbackInfo &info);
    void SetPositionScale(const Napi::CallbackInfo &info); 

    Napi::Value CreateAudioStream(const Napi::CallbackInfo &info);
    
    // Stats and diagnostics methods
    Napi::Value GetConnectionStats(const Napi::CallbackInfo &info);
    Napi::Value GetConnectionId(const Napi::CallbackInfo &info);
    Napi::Value GetJitterStats(const Napi::CallbackInfo &info);
};

#endif //ODIN_NODEJS_ODINROOM_H
