#ifndef PIXELDEFENSE_COMPONENTS_H
#define PIXELDEFENSE_COMPONENTS_H

#include <breeze.h>
#include <flecs.h>

#include "game_tileset.h"

// Needed, so we can clean up all game created entities
extern ECS_TAG_DECLARE(GameEntity);

typedef enum ResourceType {
    RES_IRON,
    RES_WOOD,
    RES_GOLD,
    RES_FOOD,
    RES_COUNT,
} ResourceType;

static const char *getResourceTypePrettyName(ResourceType type) {
    switch (type) {
        case RES_IRON: return "Iron";
        case RES_WOOD: return "Wood";
        case RES_GOLD: return "Gold";
        case RES_FOOD: return "Food";
        default:       return "Invalid";
    }
}

typedef struct Resource {
    ResourceType type;
    i32 amount;
} Resource;
extern ECS_COMPONENT_DECLARE(Resource);

typedef struct Owner {
    int32_t playerID;
} Owner;
extern ECS_COMPONENT_DECLARE(Owner);



/**********************************************************
 * Movement components
 *********************************************************/

typedef BzSpatialGridID SpatialGridID;
extern ECS_COMPONENT_DECLARE(SpatialGridID);

typedef Vector2 Position, Size, Velocity, TargetPosition, Steering;
typedef f32 Rotation, Orientation;

extern ECS_COMPONENT_DECLARE(Position);
extern ECS_COMPONENT_DECLARE(Size);
extern ECS_COMPONENT_DECLARE(Velocity);
extern ECS_COMPONENT_DECLARE(Rotation);
extern ECS_COMPONENT_DECLARE(Orientation);
extern ECS_COMPONENT_DECLARE(Steering);
extern ECS_COMPONENT_DECLARE(TargetPosition);

#define PATH_DATA_SIZE 8
typedef struct PathData {
    Position waypoints[PATH_DATA_SIZE];
    size_t numWaypoints;
    struct PathData *next;
} PathData;

typedef struct Path {
    PathData *paths;
    i32 curWaypoint;
} Path;
extern ECS_COMPONENT_DECLARE(Path);

/**********************************************************
 * Render components
 *********************************************************/

typedef struct TextureRegion {
    Texture2D texture;
    Rectangle rec;
    bool flipX : 1;
    bool flipY : 1;
} TextureRegion;
extern ECS_COMPONENT_DECLARE(TextureRegion);

/**********************************************************
 * Animation components
 *********************************************************/

typedef struct Animation {
    EntityType entityType;
    AnimType   animType;

    AnimationFrame    frame;
    AnimationSequence sequence;
    BzTileset         *tileset;

    i32 curFrame;
    f32 elapsed;
} Animation;
extern ECS_COMPONENT_DECLARE(Animation);

typedef struct Easing {
    ecs_entity_t compID;
    size_t       memberOffset;

    BzEaseType easingFunc;

    // start + target * (easeStart + (easeTarget * x) + easeOffset) + offset
    f32 target;
    f32 start;
    f32 offset;
    f32 easeTarget;
    f32 easeStart;
    f32 easeOffset;

    f32 x;
    f32 elapsed;
    f32 duration;
    //struct Easing *next;
} Easing;
extern ECS_COMPONENT_DECLARE(Easing);

/**********************************************************
 * Event components
 *********************************************************/
 typedef struct HarvestEvent {
     i32 amount;
 } HarvestEvent;
 typedef struct DepositEvent {
     i32 amount;
 } DepositEvent;

/**********************************************************
 * Gameplay components
 *********************************************************/

typedef struct WeaponMelee {
    ecs_entity_t weapon;
    f32 reach;
    f32 damage;
    f32 speed;
} WeaponMelee;
typedef struct WeaponRanged {
    ecs_entity_t weapon;
    int32_t ammo;
} WeaponRanged;
typedef struct WeaponShield {
    ecs_entity_t weapon;
} WeaponShield;
typedef struct Arms {
    ecs_entity_t primary;
    ecs_entity_t secondary;
} Arms;
extern ECS_COMPONENT_DECLARE(Arms);
typedef struct Arm {
    f32 offset;
    f32 extended;
} Arm;
extern ECS_COMPONENT_DECLARE(Arm);

extern ECS_COMPONENT_DECLARE(BzBTState);
extern ECS_COMPONENT_DECLARE(AIBlackboard);

extern ECS_TAG_DECLARE(Selectable);
extern ECS_TAG_DECLARE(Selected);

// Worker can:
// - Harvest
// - Build
// - Work
// - Attack (since it is also a unit)
typedef struct Worker {
    // stats
    f32 collectSpeed;
    f32 depositSpeed;

    i32          carry;
    i32          carryCapacity;
    ResourceType carryRes;
} Worker;
extern ECS_COMPONENT_DECLARE(Worker);

// Unit can:
// - Attack
typedef struct Unit {
    f32 maxSpeed;
    f32 acceleration;
    f32 deceleration;
} Unit;
extern ECS_COMPONENT_DECLARE(Unit);
typedef struct Building {
    BuildingType type;
    Vec2i pos;
    Vec2i size;
} Building;
extern ECS_COMPONENT_DECLARE(Building);
extern ECS_TAG_DECLARE(Storage);
extern ECS_TAG_DECLARE(Harvestable);
extern ECS_TAG_DECLARE(Buildable);
extern ECS_TAG_DECLARE(Workable);
extern ECS_TAG_DECLARE(Attackable);

void initComponentIDs(ecs_world_t *ecs);

void igTagCheckbox(const char *label, ecs_world_t *ecs,
                   ecs_entity_t entity, ecs_entity_t tag);

typedef void(*ImGuiCompFn)(ecs_world_t *ecs, ecs_entity_t entity, ecs_entity_t comp);
void igResource(ecs_world_t *ecs,
                ecs_entity_t entity, ecs_entity_t comp);
void igOwner(ecs_world_t *ecs,
             ecs_entity_t entity, ecs_entity_t comp);

void igSpatialGridID(ecs_world_t *ecs,
                     ecs_entity_t entity, ecs_entity_t comp);
void igVec2Comp(ecs_world_t *ecs,
                ecs_entity_t entity, ecs_entity_t comp);
void igFloat(ecs_world_t *ecs,
            ecs_entity_t entity, ecs_entity_t comp);

void igPath(ecs_world_t *ecs,
            ecs_entity_t entity, ecs_entity_t comp);

void igTextureRegion(ecs_world_t *ecs,
                     ecs_entity_t entity, ecs_entity_t comp);

void igAnimation(ecs_world_t *ecs,
                 ecs_entity_t entity, ecs_entity_t comp);
void igEasing(ecs_world_t *ecs,
              ecs_entity_t entity, ecs_entity_t comp);

void igArms(ecs_world_t *ecs,
            ecs_entity_t entity, ecs_entity_t comp);
void igArm(ecs_world_t *ecs,
           ecs_entity_t entity, ecs_entity_t comp);

void igVisualizeBTState(const BzBTNode *node, const BzBTNodeState *state,
                        bool isActive, bool sameLine, i32 depth);
void igBzBTState(ecs_world_t *ecs,
                 ecs_entity_t entity, ecs_entity_t comp);
void igAIBlackboard(ecs_world_t *ecs,
                    ecs_entity_t entity, ecs_entity_t comp);

void igWorker(ecs_world_t *ecs,
              ecs_entity_t entity, ecs_entity_t comp);
void igUnit(ecs_world_t *ecs,
            ecs_entity_t entity, ecs_entity_t comp);

#endif //PIXELDEFENSE_COMPONENTS_H
