#include "../utils.h"
#include "../factory_objects.h"
#include "../resources.h"
#include "../level.h"
#include "../camera.h"
#include "../particles.h"

typedef struct actor_hammer_s
{
    object_t *self_object;
    sprite_t *sprite;
    vector_t  start_position;
    vector_t  position;
    vector_t  velocity;
    bool      on_ground;
    bool      raising;
    int       length;
} actor_hammer_t;

static void _Actor_Hammer_CreateAnimations(actor_hammer_t *actor)
{
    Sprite_AnimationAdd(actor->sprite, "idle", 8);
    Sprite_AnimationAddFrame(actor->sprite, "idle", Utils_GetRect(0, 3, 16, 10));
}

static void _Actor_Hammer_GetInfo(actor_hammer_t *actor, object_info_t *info)
{
    if (actor == NULL)
        return;

    if (info == NULL)
        return;

    info->box_rect       = Utils_GetRect(0, 0, 48, 30);
    info->collision_rect = Utils_GetRect(0, 0, 48, 30);
    info->position       = actor->position;

    if (actor->sprite != NULL)
    {
        info->box_rect.x = actor->position.x - actor->sprite->origin.x;
        info->box_rect.y = actor->position.y - actor->sprite->origin.y;

        info->collision_rect.x = actor->position.x - actor->sprite->origin.x;
        info->collision_rect.y = actor->position.y - actor->sprite->origin.y;
    }

    info->collision_cell_ul.x = info->collision_rect.x / CELL_WIDTH;
    info->collision_cell_ul.y = info->collision_rect.y / CELL_HEIGHT;
    info->collision_cell_br.x = (info->collision_rect.x + info->collision_rect.w) / CELL_WIDTH;
    info->collision_cell_br.y = (info->collision_rect.y + info->collision_rect.h) / CELL_HEIGHT;
}

static void _Actor_Hammer_Collision(actor_hammer_t *actor, void *actor_collision, actor_type_t actor_type)
{
    if (actor == NULL)
        return;

    if (actor_collision == NULL)
        return;

    if (actor_type == AT_ROBO)
    {
        if (actor->on_ground)
            Actor_Robo_Kill(actor_collision);
    }
}

static void _Actor_Hammer_Update(actor_hammer_t *actor, float dt)
{
    if (actor == NULL)
        return;

    object_info_t info;
    float         correct_y  = 0;

    if (!actor->raising)
    {
        if (!actor->on_ground)
            actor->velocity.y += ACTOR_GRAVITY;
    }

    actor->position.y += actor->velocity.y;
    actor->on_ground   = false;

    _Actor_Hammer_GetInfo(actor, &info);

    bool test_colly = Level_CheckCollision(info, actor->velocity, false, &correct_y);

    if (test_colly)
    {
        actor->position.y = correct_y;

        if (actor->velocity.y < 0)
        {
            actor->raising    = false;
            actor->velocity.y = 0;
        }

        if (actor->velocity.y > 0)
        {
            actor->raising    = true;
            actor->on_ground  = true;
            actor->velocity.y = -ACTOR_HAMMER_VELOCITY_VERTICAL;

            Particles_SpawnGroundParticles(actor->position.x - 12, actor->position.y + 24);
            Particles_SpawnGroundParticles(actor->position.x + 12, actor->position.y + 24);

            vector_t robo_position = Camera_GetFollowPosition();

            if (Utils_PointInCircle(robo_position, actor->position, ACTOR_HAMMER_SHAKE_RADIUS))
                Camera_Shake();
        }
    }

    actor->length = actor->position.y - actor->start_position.y;

    if (actor->length < 0)
        actor->length = 0;

    if (actor->length > ACTOR_HAMMER_MAX_LENGTH)
    {
        actor->raising    = true;
        actor->velocity.y = -ACTOR_HAMMER_VELOCITY_VERTICAL;
    }

    Sprite_Update(actor->sprite);
}

static void _Actor_Hammer_Draw(SDL_Renderer *renderer, actor_hammer_t *actor)
{
    if (actor == NULL)
        return;

    SDL_Rect holder_frame = Utils_GetRect(0, 0, 16, 3);
    SDL_Rect holder_draw  = Utils_GetRect(actor->start_position.x - 24, actor->start_position.y, 48, 8);

    SDL_Rect rope_frame = Utils_GetRect(0, 13, 16, (Uint32)(actor->length / 3) - 1);
    SDL_Rect rope_draw  = Utils_GetRect(actor->start_position.x - 24, actor->start_position.y + 3, 48, actor->length-1);

    Camera_Draw(renderer, hammerTex, &holder_frame, &holder_draw);

    if (actor->sprite != NULL)
        Sprite_Draw(renderer, actor->sprite, actor->position);

    Camera_Draw(renderer, hammerTex, &rope_frame, &rope_draw);
}

static void _Actor_Hammer_Free(actor_hammer_t *actor)
{
    if (actor == NULL)
        return;

    Sprite_Free(actor->sprite);

    free(actor);

    actor = NULL;
}

void Actor_Hammer_Create(object_t *object, float x, float y)
{
    if (object != NULL)
    {
        actor_hammer_t *actor = (actor_hammer_t*)malloc(sizeof(actor_hammer_t));

        actor->self_object = object;

        FactoryObjects_SetActor(object, (void*)actor, AT_HAMMER, OLAY_TILES);

        FactoryObjects_SetFunc(object, _Actor_Hammer_GetInfo,   OFUNC_GETINFO);
        FactoryObjects_SetFunc(object, _Actor_Hammer_Collision, OFUNC_COLLISION);
        FactoryObjects_SetFunc(object, _Actor_Hammer_Update,    OFUNC_UPDATE);
        FactoryObjects_SetFunc(object, _Actor_Hammer_Draw,      OFUNC_DRAW);
        FactoryObjects_SetFunc(object, _Actor_Hammer_Free,      OFUNC_FREE);

        actor->sprite          = Sprite_Create(Utils_GetPoint(24, 6), 48, 30, hammerTex);
        actor->position        = Utils_GetVector(x, y + 6);
        actor->start_position  = Utils_GetVector(x, y);
        actor->velocity        = Utils_GetVector(0, 0);
        actor->on_ground       = false;
        actor->raising         = false;
        actor->length          = 0;

        _Actor_Hammer_CreateAnimations(actor);

        Sprite_AnimationPlay(actor->sprite, "idle", true);
    }
}
