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

typedef struct actor_circularsaw_s
{
    object_t *self_object;
    sprite_t *sprite;
    vector_t  position;
    vector_t  velocity;
    bool      on_ground;
    bool      flip;
    int       angle_saw;
} actor_circularsaw_t;

static void _Actor_Circularsaw_CreateAnimations(actor_circularsaw_t *actor)
{
    Sprite_AnimationAdd(actor->sprite, "move", 5);
    Sprite_AnimationAddFrame(actor->sprite, "move", Utils_GetRect(0,  24, 24, 24));
    Sprite_AnimationAddFrame(actor->sprite, "move", Utils_GetRect(24, 24, 24, 24));
    Sprite_AnimationAddFrame(actor->sprite, "move", Utils_GetRect(48, 24, 24, 24));
    Sprite_AnimationAddFrame(actor->sprite, "move", Utils_GetRect(72, 24, 24, 24));
}

static void _Actor_Circularsaw_GetInfo(actor_circularsaw_t *actor, object_info_t *info)
{
    if (actor == NULL)
        return;

    if (info == NULL)
        return;

    info->box_rect       = Utils_GetRect(0, 0, 72, 72);
    info->collision_rect = Utils_GetRect(0, 0, 42, 48);
    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 - 21;
        info->collision_rect.y = actor->position.y - 21;
    }

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

    if (actor_collision == NULL)
        return;

    if (actor_type == AT_ROBO)
    {
        Actor_Robo_Kill(actor_collision);
    }
}

static void _Actor_Circularsaw_Update(actor_circularsaw_t *actor, float dt)
{
    if (actor == NULL)
        return;

    object_info_t info;
    float         correct_x = 0;
    float         correct_y = 0;
    bool          turn_right = false;

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

    _Actor_Circularsaw_GetInfo(actor, &info);

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

    if (test_collx)
    {
        actor->position.x = correct_x;

        if (!actor->flip)
        {
            actor->flip = true;
            actor->velocity.x = -ACTOR_CIRCULARSAW_VELOCITY_HORIZONTAL;
        }
        else
        {
            actor->flip = false;
            actor->velocity.x = ACTOR_CIRCULARSAW_VELOCITY_HORIZONTAL;
        }

        Sprite_SetFlip(actor->sprite, actor->flip);
    }

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

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

    _Actor_Circularsaw_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->on_ground  = true;
    }

    _Actor_Circularsaw_GetInfo(actor, &info);

    bool turn = Level_CheckTurn(info, &turn_right);
    if (turn)
    {
        if (turn_right)
        {
            if (actor->flip)
            {
                actor->flip = false;
                actor->velocity.x = ACTOR_CIRCULARSAW_VELOCITY_HORIZONTAL;
            }
        }
        else
        {
            if (!actor->flip)
            {
                actor->flip = true;
                actor->velocity.x = -ACTOR_CIRCULARSAW_VELOCITY_HORIZONTAL;
            }
        }

        Sprite_SetFlip(actor->sprite, actor->flip);
    }

    actor->angle_saw += 5;

    if (actor->angle_saw > 359)
        actor->angle_saw = 0;

    Sprite_Update(actor->sprite);
}

static void _Actor_Circularsaw_Draw(SDL_Renderer *renderer, actor_circularsaw_t *actor)
{
    if (actor == NULL)
        return;

    SDL_Rect saw_frame = Utils_GetRect(102, 6, 36, 36);
    SDL_Rect saw_draw  = Utils_GetRect(actor->position.x-30, actor->position.y-40, 60, 60);

    Camera_DrawEx(renderer, circularsawTex, &saw_frame, &saw_draw, actor->angle_saw, NULL, SDL_FLIP_NONE);

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

static void _Actor_Circularsaw_Free(actor_circularsaw_t *actor)
{
    if (actor == NULL)
        return;

    Sprite_Free(actor->sprite);

    free(actor);

    actor = NULL;
}

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

        actor->self_object = object;

        FactoryObjects_SetActor(object, (void*)actor, AT_CIRCULARSAW, OLAY_ENEMYES);

        FactoryObjects_SetFunc(object, _Actor_Circularsaw_GetInfo,   OFUNC_GETINFO);
        FactoryObjects_SetFunc(object, _Actor_Circularsaw_Collision, OFUNC_COLLISION);
        FactoryObjects_SetFunc(object, _Actor_Circularsaw_Update,    OFUNC_UPDATE);
        FactoryObjects_SetFunc(object, _Actor_Circularsaw_Draw,      OFUNC_DRAW);
        FactoryObjects_SetFunc(object, _Actor_Circularsaw_Free,      OFUNC_FREE);

        actor->sprite    = Sprite_Create(Utils_GetPoint(36, 45), 72, 72, circularsawTex);
        actor->position  = Utils_GetVector(x, y);
        actor->velocity  = Utils_GetVector(ACTOR_CIRCULARSAW_VELOCITY_HORIZONTAL, 0);
        actor->on_ground = false;
        actor->flip      = false;
        actor->angle_saw = 0;

        _Actor_Circularsaw_CreateAnimations(actor);

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