#ifndef _fencer_collidable_h
#define _fencer_collidable_h

#include "vmath.h"
#include "typeclass_helpers.h"
#include "list.h"
#include "shape.h"

typedef struct Collision Collision;
typedef struct RigidBody RigidBody;
typedef struct PhysicsEntity PhysicsEntity;

typedef struct IPhysicsEntity {
    RigidBody* (*const get_rigidbody)(void* self);
    Shape* (*const get_shape)(void* self);
    void(*const on_collision)(void* self, Collision collision);
    void(*const on_overlap)(void* self, PhysicsEntity other);
} IPhysicsEntity;

typedef struct PhysicsEntity {
    void* data;
    IPhysicsEntity const* tc;
    ITransformable const* transformable;
} PhysicsEntity;

extern void physics_entity_debug_draw(PhysicsEntity self);
extern void physics_entity_solve_contacts(PhysicsEntity self, List* contacts);
extern void physics_entity_update(PhysicsEntity self);


#define impl_PhysicsEntity_for(T, get_rigidbody_f, get_shape_f, on_collision_f, on_overlap_f)\
static inline PhysicsEntity T##_as_PhysicsEntity(T* x) {\
    TC_FN_TYPECHECK(Transformable, T##_as_Transformable, T*);\
    TC_FN_TYPECHECK(RigidBody*, get_rigidbody_f, T*);\
    TC_FN_TYPECHECK(Shape*, get_shape_f, T*);\
    TC_FN_TYPECHECK(void, on_collision_f, T*, Collision);\
    TC_FN_TYPECHECK(void, on_overlap_f, T*, PhysicsEntity);\
    static IPhysicsEntity const tc = {\
        .get_rigidbody =     (RigidBody*(*const)(void*))            get_rigidbody_f,\
        .get_shape =         (Shape*(*const)(void*))                get_shape_f,\
        .on_collision =      (void(*const)(void*,Collision))        on_collision_f,\
        .on_overlap =        (void(*const)(void*,PhysicsEntity))    on_overlap_f,\
    };\
    Transformable transformable = T##_as_Transformable(x);\
    return (PhysicsEntity){.data = x, .tc = &tc, .transformable = transformable.tc};\
}

#endif // !_fencer_collidable_h