#if defined(__clang__)
#pragma once
#include "feely_pona_unity.h"
#endif

enum FP_GameEntityFlag
{
    FP_GameEntityFlag_Clickable                           = 1 << 0,
    FP_GameEntityFlag_MoveByKeyboard                      = 1 << 1,
    FP_GameEntityFlag_MoveByMouse                         = 1 << 2,
    FP_GameEntityFlag_DrawHitBox                          = 1 << 3,
    FP_GameEntityFlag_DeriveHitBoxFromChildrenBoundingBox = 1 << 4,
    FP_GameEntityFlag_NonTraversable                      = 1 << 5,
    FP_GameEntityFlag_MobSpawner                          = 1 << 6,
};

enum FP_GameShapeType
{
    FP_GameShapeType_None,
    FP_GameShapeType_Circle,
    FP_GameShapeType_Rect,
    FP_GameShapeType_Line,
};

struct FP_GameShape
{
    FP_GameShapeType     type;
    Dqn_V2               p1;
    Dqn_V2               p2;
    Dqn_V4               colour;
    Dqn_f32              line_thickness;
    Dqn_f32              circle_radius;
    TELY_RenderShapeMode render_mode;
};

const uint64_t FP_GAME_ENTITY_HANDLE_GENERATION_MASK   = 0xFFFF'0000'0000'0000;
const uint64_t FP_GAME_ENTITY_HANDLE_GENERATION_RSHIFT = 48;
const uint64_t FP_GAME_ENTITY_HANDLE_GENERATION_MAX    = FP_GAME_ENTITY_HANDLE_GENERATION_MASK >> FP_GAME_ENTITY_HANDLE_GENERATION_RSHIFT;

const uint64_t FP_GAME_ENTITY_HANDLE_INDEX_MASK        = 0x0000'FFFF'FFFF'FFFF;
const uint64_t FP_GAME_ENTITY_HANDLE_INDEX_MAX         = FP_GAME_ENTITY_HANDLE_INDEX_MASK - 1;
struct FP_GameEntityHandle
{
    uint64_t id;
};

enum FP_GameEntityState
{
    FP_GameEntityState_Nil,
    FP_GameEntityState_Idle,
    FP_GameEntityState_AttackA,
    FP_GameEntityState_AttackB,
    FP_GameEntityState_AttackC,
    FP_GameEntityState_Run,
    FP_GameEntityState_Dash,
};

struct FP_GameWaypoint
{
    Dqn_V2I          pos;
    FP_GameWaypoint *next;
    FP_GameWaypoint *prev;
};

enum FP_GameEntityActionFlag
{
    FP_GameEntityActionFlag_StateTransition = 1 << 0,
    FP_GameEntityActionFlag_Failed          = 1 << 1,
};

Dqn_f32 const FP_GAME_ENTITY_ACTION_INFINITE_TIMER = -1.f;
struct FP_GameEntityAction
{
    FP_GameEntityState         state;
    uint32_t                   flags; // Bit flags corresponding with `FP_GameEntityActionFlag`
    TELY_AssetSpriteAnimation *anim;
    Dqn_f32                    timer_s;
    Dqn_f32                    end_at_s;
};

struct FP_GameEntity
{
    FP_GameEntity                         *next;
    FP_GameEntity                         *prev;
    FP_GameEntity                         *first_child;
    FP_GameEntity                         *last_child;
    FP_GameEntity                         *parent;

    Dqn_String8                            name;
    FP_GameEntityHandle                    handle;
    TELY_AssetSpriteSheet                 *sprite_sheet;
    Dqn_Slice<TELY_AssetSpriteAnimation>   sprite_anims;
    Dqn_V2                                 size_scale;
    FP_GameEntityAction                    action;
    Dqn_V2                                 velocity;

    FP_GameEntityHandle                    stalk_entity;
    Dqn_V2I                                stalk_entity_last_known_tile;
    FP_GameWaypoint                       *waypoints;

    // NOTE: The entity hit box is positioned at the center of the entity.
    Dqn_V2                                 local_hit_box_size;
    Dqn_V2                                 local_hit_box_offset;

    Dqn_V2                                 attack_box_size;
    Dqn_V2                                 attack_box_offset;

    uint64_t                               next_spawn_timestamp_s;

    uint64_t                               flags;
    bool                                   facing_left;
    Dqn_V2                                 local_pos;
    Dqn_f64                                alive_time_s;
    Dqn_FArray<FP_GameShape, 4>            shapes;
};

struct FP_GameEntityIterator
{
    bool           init;
    Dqn_usize      iteration_count;

    FP_GameEntity *entity;
    FP_GameEntity *last_visited;

    FP_GameEntity *entity_parent;
    FP_GameEntity *entity_next;
    FP_GameEntity *entity_first_child;
};

struct FP_GameCamera
{
    Dqn_V2  world_pos;
    Dqn_f32 rotate_rads;
    Dqn_V2  scale;
};

struct FP_Game
{
    Dqn_f32                              delta_s_accumulator;
    uint16_t                             tile_size;
    TELY_ChunkPool                      *chunk_pool;
    TELY_AssetFontHandle                 inter_regular_font;
    TELY_AssetFontHandle                 inter_italic_font;
    TELY_AssetFontHandle                 jetbrains_mono_font;
    TELY_AssetAudioHandle                test_audio;
    Dqn_Slice<TELY_AssetSpriteAnimation> hero_sprite_anims;
    TELY_AssetSpriteSheet                hero_sprite_sheet;
    Dqn_FArray<FP_GameEntityHandle, 8>   parent_entity_stack;
    Dqn_VArray<FP_GameEntity>            entities;

    TELY_AssetSpriteSheet                protag_walk_sprite_sheet;
    Dqn_Slice<TELY_AssetSpriteAnimation> protag_walk_sprite_anims;

    FP_GameEntity                       *root_entity;
    FP_GameEntity                       *entity_free_list;

    FP_GameEntityHandle                  player;

    FP_GameEntityHandle                  clicked_entity;
    FP_GameEntityHandle                  hot_entity;
    FP_GameEntityHandle                  active_entity;
    FP_GameEntityHandle                  prev_clicked_entity;
    FP_GameEntityHandle                  prev_hot_entity;
    FP_GameEntityHandle                  prev_active_entity;

    FP_GameCamera                        camera;
    TELY_RFui                            rfui;
};

struct FP_GameAStarNode
{
    Dqn_usize cost;
    Dqn_usize heuristic;
    Dqn_V2I   tile;
    Dqn_V2I   came_from;
    bool      non_traversable;
};
