#include "systems.h"

#include "../game_state.h"

#include <raymath.h>

void updateAnimationState(ecs_iter_t *it) {
    Animation *anim = ecs_field(it, Animation, 1);
    TextureRegion *text = ecs_field(it, TextureRegion, 2);
    for (i32 i = 0; i < it->count; i++) {
        ecs_entity_t entity = it->entities[i];
        AnimType type = ANIM_IDLE;
        if (ecs_has(ECS, entity, Velocity)) {
            Velocity vel = *ecs_get(ECS, entity, Velocity);
            f32 len = Vector2Length(vel);
            if (len > 1.0f) {
                type = ANIM_WALK;
                text[i].flipX = vel.x < 0;
            }
        }

        if (type != anim[i].animType) {
            anim[i].animType = type;
            anim[i].sequence = entityGetAnimationSequence(anim[i].entityType, type);
            anim[i].curFrame = 0;
            anim[i].elapsed  = 0;
        }
    }
}
void updateAnimation(ecs_iter_t *it) {
    Game          *game    = ecs_singleton_get_mut(ECS, Game);
    Animation     *anim    = ecs_field(it, Animation, 1);
    TextureRegion *texture = ecs_field(it, TextureRegion, 2);

    float dt = GetFrameTime();

    for (i32 i = 0; i < it->count; i++) {
        AnimationFrame    frame = anim[i].frame;
        AnimationSequence seq   = anim[i].sequence;

        anim[i].elapsed += dt;
        if (anim[i].elapsed < frame.duration) continue;

        i32 nextFrame    = (anim[i].curFrame + 1) % seq.frameCount;
        anim[i].curFrame = nextFrame;
        anim[i].frame    = entityGetAnimationFrame(anim[i].entityType, anim[i].animType, nextFrame);
        anim[i].elapsed  = 0.0f;

        texture[i].rec = bzTilesetGetTileRegion(anim[i].tileset, anim[i].frame.frame);
    }
}

void updateEasingSystem(ecs_iter_t *it) {
    Easing *easing = ecs_field(it, Easing, 1);

    f32 dt = GetFrameTime();

    for (i32 i = 0; i < it->count; i++) {
        ecs_entity_t entity = it->entities[i];
        if (easing[i].elapsed > easing[i].duration) {
            ecs_remove(ECS, entity, Easing);
            continue;
        }
        if (!ecs_has_id(ECS, entity, easing[i].compID))
            continue;
        easing[i].elapsed += dt;
        f32 alpha = easing[i].elapsed / easing[i].duration;
        alpha = BZ_MIN(1.0f, alpha);
        f32 prevX = easing[i].x;
        easing[i].x = bzEase(easing[i].easingFunc, alpha);

        const Easing *e = &easing[i];
        f32 x = e->x;
        // Inner
        x = e->easeStart + e->easeTarget * x + e->easeOffset;
        // Outer
        x = e->start + e->target * x + e->offset;
        easing[i].x = x;

        u8 *compData = ecs_get_mut_id(ECS, entity, easing[i].compID);
        compData += easing[i].memberOffset;
        f32 *out = (f32 *) compData;

        *out -= prevX;
        *out += x;
    }
}
