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

typedef struct actor_fireball_s
{
    object_t *self_object;
    sprite_t *sprite;
    vector_t  position;
    vector_t  velocity;
    int       sleep_smoke;
} actor_fireball_t;

static void _Actor_Fireball_CreateAnimations(actor_fireball_t *actor)
{
    Sprite_AnimationAdd(actor->sprite, "idle", 8);
    Sprite_AnimationAddFrame(actor->sprite, "idle", Utils_GetRect(0, 0, 10, 10));
}

static void _Actor_Fireball_GetInfo(actor_fireball_t *actor, object_info_t *info)
{
    if (actor == NULL)
        return;

    if (info == NULL)
        return;

    info->box_rect       = Utils_GetRect(0, 0, 0, 0);
    info->collision_rect = Utils_GetRect(0, 0, 0, 0);
    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->box_rect.w = actor->sprite->width;
        info->box_rect.h = actor->sprite->height;

        info->collision_rect.x = actor->position.x - 6;
        info->collision_rect.y = actor->position.y - 6;
        info->collision_rect.w = 12;
        info->collision_rect.h = 12;
    }

    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_Fireball_Collision(actor_fireball_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_Robo_IsHit(actor_collision))
        {
            Actor_Robo_Hit(actor_collision);
            FactoryObjects_SignRemove(actor->self_object);
        }
    }
}

static void _Actor_Fireball_Update(actor_fireball_t *actor, float dt)
{
    if (actor == NULL)
        return;

    object_info_t info;
    float         correct_x = 0;
    float         correct_y = 0;

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

    _Actor_Fireball_GetInfo(actor, &info);

    bool test_collx = Level_CheckCollision(info, actor->velocity, true, &correct_x);

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

    _Actor_Fireball_GetInfo(actor, &info);

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

    if (test_collx || test_colly)
    {
        Particles_SpawnGroundParticles(actor->position.x, actor->position.y);
        FactoryObjects_SignRemove(actor->self_object);
    }

    if ((actor->position.x < 0) ||
        (actor->position.y < 0) ||
        (actor->position.x > Level_GetWidth()) ||
        (actor->position.y > Level_GetHeight()))
        FactoryObjects_SignRemove(actor->self_object);

    actor->sleep_smoke++;

    if (actor->sleep_smoke > 3)
    {
        actor->sleep_smoke = 0;

        object_t* obj_smoke = FactoryObjects_Create();
        Actor_Smoke_Create(obj_smoke, actor->position.x, actor->position.y);
    }

    Sprite_Update(actor->sprite);
}

static void _Actor_Fireball_Draw(SDL_Renderer *renderer, actor_fireball_t *actor)
{
    if (actor == NULL)
        return;

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

static void _Actor_Fireball_Free(actor_fireball_t *actor)
{
    if (actor == NULL)
        return;

    Sprite_Free(actor->sprite);

    free(actor);

    actor = NULL;
}

void Actor_Fireball_Create(object_t *object, int direction, float x, float y)
{
    if (object != NULL)
    {
        actor_fireball_t *actor = (actor_fireball_t*)malloc(sizeof(actor_fireball_t));

        actor->self_object = object;

        FactoryObjects_SetActor(object, (void*)actor, AT_FIREBALL, OLAY_BULLETS);

        FactoryObjects_SetFunc(object, _Actor_Fireball_GetInfo,   OFUNC_GETINFO);
        FactoryObjects_SetFunc(object, _Actor_Fireball_Collision, OFUNC_COLLISION);
        FactoryObjects_SetFunc(object, _Actor_Fireball_Update,    OFUNC_UPDATE);
        FactoryObjects_SetFunc(object, _Actor_Fireball_Draw,      OFUNC_DRAW);
        FactoryObjects_SetFunc(object, _Actor_Fireball_Free,      OFUNC_FREE);

        actor->sprite      = Sprite_Create(Utils_GetPoint(15, 15), 30, 30, fireballTex);
        actor->position    = Utils_GetVector(x, y);
        actor->velocity    = Utils_GetVector(0, 0);
        actor->sleep_smoke = 0;

        switch(direction)
        {
            case 0  : actor->velocity.y = -3.0f; break;
            case 1  : actor->velocity.x =  3.0f; break;
            case 2  : actor->velocity.y =  3.0f; break;
            case 3  : actor->velocity.x = -3.0f; break;
        }

        _Actor_Fireball_CreateAnimations(actor);

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