#pragma once
#include <cstdint>
#include <string>
#include <optional>

// -------------------------------------------------------------------------
// Primitive math types
// -------------------------------------------------------------------------

struct Vector3 {
    float x = 0.0f;
    float y = 0.0f;
    float z = 0.0f;
};

// -------------------------------------------------------------------------
// Local player
// -------------------------------------------------------------------------

struct LocalPlayerData {
    uint64_t entityAddress      = 0;
    uint64_t visualStateAddress = 0;
    Vector3  position;
    float    lookDirection      = 0.0f; // heading in degrees
};

// -------------------------------------------------------------------------
// Network / server metadata
// -------------------------------------------------------------------------

struct NetworkMetadata {
    std::string              serverName;
    std::string              gameVersion;
    std::optional<std::string> serverMapName;
};

// -------------------------------------------------------------------------
// Scoreboard
// -------------------------------------------------------------------------

struct DayZScoreboardPlayer {
    uint32_t    networkId  = 0;
    std::string steamId;
    std::string playerName;
};

// -------------------------------------------------------------------------
// Near entity list
// -------------------------------------------------------------------------

struct DayZNearEntityEntry {
    uint64_t                   address     = 0;
    uint32_t                   networkId   = 0;
    std::optional<Vector3>     position;
    std::optional<float>       headingDegrees;
    std::string                entityName;
    std::string                typeName;
    std::string                configName;
    std::string                modelName;
};

// -------------------------------------------------------------------------
// Far entity list  (same schema as near)
// -------------------------------------------------------------------------

struct DayZFarEntityEntry {
    uint64_t                   address     = 0;
    uint32_t                   networkId   = 0;
    std::optional<Vector3>     position;
    std::optional<float>       headingDegrees;
    std::string                entityName;
    std::string                typeName;
    std::string                configName;
    std::string                modelName;
};

// -------------------------------------------------------------------------
// Slow entity list  (no networkId)
// -------------------------------------------------------------------------

struct DayZSlowEntityEntry {
    uint64_t                   address     = 0;
    std::optional<Vector3>     position;
    std::optional<float>       headingDegrees;
    std::string                entityName;
    std::string                typeName;
    std::string                configName;
    std::string                modelName;
};

// -------------------------------------------------------------------------
// Skeleton bones (12 named bones used for segment rendering)
// Layout matches Spectre PLAYER_BONE_IDS / INFECTED_BONE_IDS segment topology.
// -------------------------------------------------------------------------

// Bone layout mirrors Spectre stable segments.
// Player:  spine→neck→head; neck→shoulders→elbows→hands; spine→hips→knees→ankles
// Zombie:  spine→neck→head; spine→shoulders→elbows→hands; spine→pelvis→hips→knees→ankles
struct SkeletonBones {
    Vector3 neck;
    Vector3 head;
    Vector3 spine;          // chest hub (player bone 18, zombie bone 19)
    Vector3 pelvis;         // zombie only — connects spine to hips
    Vector3 rightShoulder;
    Vector3 rightElbow;
    Vector3 rightHand;
    Vector3 leftShoulder;
    Vector3 leftElbow;
    Vector3 leftHand;
    Vector3 rightHip;
    Vector3 rightKnee;
    Vector3 rightAnkle;
    Vector3 leftHip;
    Vector3 leftKnee;
    Vector3 leftAnkle;
    bool    valid = false;
};

// -------------------------------------------------------------------------
// Player entry (full)
// -------------------------------------------------------------------------

struct DayZPlayerEntry {
    uint64_t                   address        = 0;
    uint32_t                   networkId      = 0;
    std::optional<Vector3>     position;
    std::optional<float>       headingDegrees;
    bool                       isDead         = false;
    bool                       isAdmin        = false;  // model matches a known invisible/admin model path
    std::string                nickname;
    std::string                itemInHands;
    std::string                typeName;
    std::string                configName;
    std::string                modelName;
    SkeletonBones              skeleton;
    // health in the range [0, 100].  -1.0f = not yet read / offset unknown.
    float                      health         = -1.0f;
};

// -------------------------------------------------------------------------
// Bullet entry
// -------------------------------------------------------------------------

struct DayZBulletEntry {
    uint64_t                   address         = 0;
    std::optional<Vector3>     position;
    std::optional<Vector3>     direction;
    std::optional<float>       headingDegrees;
    std::string                directionSource; // e.g. "visual", "raw"
};

// -------------------------------------------------------------------------
// Item list entry
// -------------------------------------------------------------------------

struct DayZItemListEntry {
    uint64_t                   address     = 0;
    std::optional<Vector3>     position;
    std::string                entityName;
    std::string                cleanName;
    std::string                typeName;
    std::string                configName;
    std::string                modelName;
    std::string                filterKey;  // lower-case composite for filtering
};

// -------------------------------------------------------------------------
// Specialised slow-list entity types
// -------------------------------------------------------------------------

struct DayZAnimalEntry {
    uint64_t                   address     = 0;
    std::optional<Vector3>     position;
    std::optional<float>       headingDegrees;
    std::string                entityName;
    std::string                typeName;
    std::string                configName;
    std::string                modelName;
};

struct DayZZombieEntry {
    uint64_t                   address     = 0;
    std::optional<Vector3>     position;
    std::optional<float>       headingDegrees;
    std::string                entityName;
    std::string                typeName;
    std::string                configName;
    std::string                modelName;
    SkeletonBones              skeleton;
};

// Vehicles: cars, boats, helicopters, etc.
enum class VehicleKind : uint8_t {
    Unknown = 0,
    Car,
    Boat,
    Helicopter,
    Plane,
};

struct DayZCarAndBoatEntry {
    uint64_t                   address     = 0;
    std::optional<Vector3>     position;
    std::optional<float>       headingDegrees;
    std::string                entityName;
    std::string                typeName;
    std::string                configName;
    std::string                modelName;
    VehicleKind                kind        = VehicleKind::Unknown;
};

struct DayZOtherEntityEntry {
    uint64_t                   address     = 0;
    std::optional<Vector3>     position;
    std::optional<float>       headingDegrees;
    std::string                entityName;
    std::string                typeName;
    std::string                configName;
    std::string                modelName;
};

// -------------------------------------------------------------------------
// Camera data (read from World+0x1B8 inline struct each frame)
// -------------------------------------------------------------------------

struct CameraData {
    Vector3 invertedViewRight;
    Vector3 invertedViewUp;
    Vector3 invertedViewForward;
    Vector3 translation;
    float   projectionD1x = 0.0f; // horizontal FOV scale
    float   projectionD2y = 0.0f; // vertical FOV scale
    bool    valid         = false;
};
