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

typedef struct actor_hook_s
{
    object_t     *self_object;
    actor_robo_t *robo;
    vector_t      position;
    vector_t      velocity;
    bool          grab;
    int           length;
} actor_hook_t;

static void _Actor_Hook_GetInfo(actor_hook_t *actor, object_info_t *info)
{
    if (actor == NULL)
        return;

    if (info == NULL)
        return;

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

    info->box_rect.x = actor->position.x - 9;
    info->box_rect.y = actor->position.y - 3;

    info->collision_rect.x = actor->position.x - 9;
    info->collision_rect.y = actor->position.y - 3;

    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_Hook_Collision(actor_hook_t *actor, void *actor_collision, actor_type_t actor_type)
{
    if (actor == NULL)
        return;
}

static void _Actor_Hook_Update(actor_hook_t *actor, float dt)
{
    if (actor == NULL)
        return;

    object_info_t info;
    float         correct_y = 0;

    if (!actor->grab)
         actor->velocity.y -= 0.6f;

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

    _Actor_Hook_GetInfo(actor, &info);

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

    if (test_colly)
    {
        actor->position.y = correct_y;
        actor->velocity.y = 0;
        actor->grab = true;

        Particles_SpawnGroundParticles(actor->position.x, actor->position.y);
        Mix_PlayChannel(-1, grabSnd, 0);

        Helper_SetHookHide();
        Helper_SetMoveVertical();
    }

    vector_t robo_position = Actor_Robo_GetPosition(actor->robo);
    actor->length          = (Uint32)robo_position.y - (Uint32)actor->position.y;

    if (actor->length > ACTOR_HOOK_MAX_LENGTH)
        Actor_Robo_HideHook(actor->robo);
}

static void _Actor_Hook_Draw(SDL_Renderer *renderer, actor_hook_t *actor)
{
    if (actor == NULL)
        return;

    Uint32 length = (Uint32)actor->length;

    SDL_Rect hook_frame_rect = Utils_GetRect(1, 1, 6, 6);
    SDL_Rect hook_draw_rect  = Utils_GetRect(0, 0, 18, 18);
    SDL_Rect rope_frame_rect = Utils_GetRect(2, 9, 6, (Uint32)(length / 3));
    SDL_Rect rope_draw_rect  = Utils_GetRect(0, 0, 12, length-15);

    hook_draw_rect.x = (Uint32)actor->position.x - 9;
    hook_draw_rect.y = (Uint32)actor->position.y - 3;

    rope_draw_rect.x = (Uint32)actor->position.x - 4;
    rope_draw_rect.y = (Uint32)actor->position.y + 12;

    Camera_Draw(renderer, hookTex, &hook_frame_rect, &hook_draw_rect);
    Camera_Draw(renderer, hookTex, &rope_frame_rect, &rope_draw_rect);
}

static void _Actor_Hook_Free(actor_hook_t *actor)
{
    if (actor == NULL)
        return;

    free(actor);

    actor = NULL;
}

actor_hook_t* Actor_Hook_Create(object_t *object, actor_robo_t *actor_robo, float x, float y)
{
    actor_hook_t *actor = NULL;

    if (object != NULL)
    {
        actor = (actor_hook_t*) malloc(sizeof(actor_hook_t));

        actor->self_object = object;
        actor->robo        = actor_robo;

        FactoryObjects_SetActor(object, (void*) actor, AT_HOOK, OLAY_HOOK);

        FactoryObjects_SetFunc(object, _Actor_Hook_GetInfo,   OFUNC_GETINFO);
        FactoryObjects_SetFunc(object, _Actor_Hook_Collision, OFUNC_COLLISION);
        FactoryObjects_SetFunc(object, _Actor_Hook_Update,    OFUNC_UPDATE);
        FactoryObjects_SetFunc(object, _Actor_Hook_Draw,      OFUNC_DRAW);
        FactoryObjects_SetFunc(object, _Actor_Hook_Free,      OFUNC_FREE);

        actor->position = Utils_GetVector(x, y);
        actor->velocity = Utils_GetVector(0, -1.1f);
        actor->grab     = false;
        actor->length   = 0;

        Camera_PlaySound(hookSnd, actor->position);
    }

    return actor;
}

bool Actor_Hook_IsGrab(actor_hook_t *actor)
{
    bool result = false;

    if (actor != NULL)
        result = actor->grab;

    return result;
}
