/*
 * session/session.h — client-side mirror of the server's channel/user state.
 *
 * Populated from ServerStateSnapshot (full snapshot) and incremental UserEvent /
 * ChannelEvent messages. Not thread-safe — always called from io_thread_.
 */
#ifndef VOICECAT_SESSION_SESSION_H
#define VOICECAT_SESSION_SESSION_H

#include <cstdint>
#include <string>
#include <utility>
#include <vector>

#ifdef VOICECAT_HAS_NET
#include "proto/voicecat.pb.h"
#endif

namespace voicecat::session {

struct Channel {
    uint32_t    id{0};
    uint32_t    parent_id{0};
    std::string name;
    std::string topic;
    bool        password_protected{false};
    uint32_t    max_users{0};
};

struct Stream {
    uint32_t    stream_id{0};
    uint32_t    ssrc{0};
    int         kind{0};
    std::string label;
    // Full effective AudioConfig (docs/protocol.md §5), as broadcast by the server in
    // StreamInfo.audio — mirrors voicecat::v1::AudioConfig field-for-field so M3 per-channel
    // tuning (mono/stereo, bitrate, FEC/DTX, application) is observable client-side, not just
    // sample_rate/frame_ms.
    uint32_t    sample_rate{48000};
    uint32_t    frame_ms{20};
    uint32_t    mode{0};                  // 0 = mono, 1 = stereo (ChannelMode)
    uint32_t    bitrate_bps{0};
    uint32_t    application{0};           // 0=VOIP, 1=AUDIO, 2=LOWDELAY (OpusApplication)
    bool        fec{false};
    uint32_t    expected_packet_loss{0};
    bool        dtx{false};
    uint32_t    complexity{0};
    bool        dred{false};
};

struct User {
    uint32_t            id{0};
    std::string         nickname;
    bool                is_guest{true};
    uint32_t            channel_id{0};
    bool                self_mic_muted{false};
    bool                self_deafened{false};
    bool                server_muted{false};
    bool                server_deafened{false};
    std::vector<Stream> streams;
};

class SessionModel {
   public:
    const std::vector<Channel>& channels() const { return channels_; }
    const std::vector<User>&    users()    const { return users_; }

    const Channel* find_channel(uint32_t id) const;
    const User*    find_user(uint32_t id) const;

    // Find the user that owns a given media ssrc, and the matching Stream entry.
    // Returns {nullptr, nullptr} if not found.
    std::pair<const User*, const Stream*> find_user_by_ssrc(uint32_t ssrc) const;

#ifdef VOICECAT_HAS_NET
    void apply_snapshot(const voicecat::v1::ServerStateSnapshot& snap);
    void apply_user_event(const voicecat::v1::UserEvent& ev);
    void apply_channel_event(const voicecat::v1::ChannelEvent& ev);
#endif

   private:
    std::vector<Channel> channels_;
    std::vector<User>    users_;
};

}  // namespace voicecat::session

#endif  // VOICECAT_SESSION_SESSION_H
