#ifndef TACTICAL_SHOOTER_STATE_SERIALIZER_H
#define TACTICAL_SHOOTER_STATE_SERIALIZER_H

#include "bitstream.h"
#include "entity.h"

#include <cstdint>
#include <unordered_map>
#include <vector>

namespace tactical_shooter {

/**
 * Serialization ranges for quantized float packing.
 * These define the min/max and precision budget for each field type.
 * Tune per-game to balance bandwidth vs accuracy.
 */
struct SerializationConfig {
    // Position (quantized to 16 bits per axis = 65536 values)
    float pos_min = -1024.0f;
    float pos_max = 1024.0f;
    uint8_t pos_bits = 16;

    // Velocity (quantized to 12 bits per axis)
    float vel_min = -32.0f;
    float vel_max = 32.0f;
    uint8_t vel_bits = 12;

    // Rotation (yaw -180..180, pitch -90..90)
    float yaw_min = -180.0f;
    float yaw_max = 180.0f;
    uint8_t yaw_bits = 12;        // ~0.09° precision

    float pitch_min = -90.0f;
    float pitch_max = 90.0f;
    uint8_t pitch_bits = 11;      // ~0.09° precision

    // Health/Armor (0..100, 7 bits = 0.79 precision)
    float health_min = 0.0f;
    float health_max = 100.0f;
    uint8_t health_bits = 7;

    // Ammo (0..255, 8 bits exact)
};

/**
 * Delta-compressed snapshot serializer for network replication.
 *
 * Writes a compact binary representation of entity states suitable for
 * 128Hz server-to-client replication. Full snapshots include all entities;
 * delta snapshots only include entities with changes since the base snapshot.
 *
 * Snapshot on-wire layout:
 *   [uint16 tick] [uint16 count] [uint16 base_tick]  <- header (6 bytes)
 *   for each entity:
 *     [uint16 entity_id] [uint32 change_mask]
 *     [changed fields per mask]
 *
 * Typical size at 128Hz, 10 entities:
 *   Full snapshot: ~300-400 bytes
 *   Delta snapshot (5 entities changed): ~150-250 bytes
 */
class StateSerializer {
public:
    explicit StateSerializer(const SerializationConfig &config = SerializationConfig{});

    /**
     * Serialize a full snapshot including all entities.
     *
     * @param stream     Output bitstream
     * @param tick       Current simulation tick number
     * @param entities   All active entities
     * @param count      Number of entities
     */
    void write_full_snapshot(
        Bitstream &stream,
        uint32_t tick,
        const Entity *const *entities,
        uint16_t count
    );

    /**
     * Serialize a delta snapshot — only entities that changed from base.
     *
     * @param stream     Output bitstream
     * @param tick       Current simulation tick number
     * @param entities   All active entities
     * @param count      Number of entities
     * @param base       Base snapshot for delta comparison
     */
    void write_delta_snapshot(
        Bitstream &stream,
        uint32_t tick,
        const Entity *const *entities,
        uint16_t count,
        const std::unordered_map<uint16_t, EntitySnapshot> &base
    );

    /**
     * Deserialize a full snapshot from a bitstream.
     */
    std::vector<EntitySnapshot> read_full_snapshot(
        Bitstream &stream,
        uint32_t *out_tick
    );

    /**
     * Deserialize a delta snapshot and apply to a base.
     */
    void read_delta_snapshot(
        Bitstream &stream,
        std::unordered_map<uint16_t, EntitySnapshot> &state
    );

    /**
     * Get the configuration.
     */
    const SerializationConfig &config() const { return config_; }

private:
    void write_entity_full(Bitstream &stream, const Entity &entity);
    void write_entity_delta(
        Bitstream &stream,
        const Entity &entity,
        const EntitySnapshot &base,
        EntitySnapshot::ChangeMask mask
    );
    EntitySnapshot read_entity(Bitstream &stream, EntitySnapshot::ChangeMask mask);
    EntitySnapshot::ChangeMask read_change_mask(Bitstream &stream);

    SerializationConfig config_;
};

} // namespace tactical_shooter

#endif // TACTICAL_SHOOTER_STATE_SERIALIZER_H
