/**
 * @file likeLike.c
 * @ingroup Enemies
 *
 * @brief Like Like enemy
 */
#include "enemy.h"
#include "item.h"
#include "message.h"
#include "object.h"
#include "save.h"

typedef struct {
    Entity base;
    u8 filler[0x18];
    u8 stolenItem;
    u8 filler2;
    u8 field_0x82;
    u8 prevSpritePriority;
} LikeLikeEntity;

extern bool32 ItemIsShield(u32);

void LikeLike_ReleasePlayer(LikeLikeEntity*);
void sub_080281A0(LikeLikeEntity*);
bool32 LikeLike_StealItem(u32);
void LikeLike_ReturnStolenItem(u32);

extern void (*const LikeLike_Functions[])(Entity*);
extern void (*const gUnk_080CC714[])(LikeLikeEntity*);

void LikeLike(Entity* this) {
    EnemyFunctionHandler(this, LikeLike_Functions);
    EnemySetFXOffset(this, 0, 1, -0x10);
}

void LikeLike_OnTick(LikeLikeEntity* this) {
    gUnk_080CC714[super->action](this);
}

void LikeLike_OnCollision(LikeLikeEntity* this) {
    if (super->hitType == 1) {
        super->action = 3;
        COLLISION_OFF(super);
        super->hitType = 0x8c;
    } else {
        if (super->action == 7) {
            LikeLike_ReleasePlayer(this);
        } else if (super->contactFlags & 0x80) {
            u8 tmp = super->contactFlags & ~0x80;
            if (tmp == 0) {
                super->action = 7;
                super->timer = 95;
                super->subtimer = tmp;
                super->flags2 &= 0xfc;
                this->prevSpritePriority = gPlayerEntity.base.spritePriority.b1;
            }
        }
    }

    if (super->health == 0) {
        super->timer = 32;
    }

    if (super->confusedTime) {
        EnemyCreateFX(super, FX_STARS);
    }

    EnemyFunctionHandlerAfterCollision(super, LikeLike_Functions);
}

void LikeLike_OnDeath(LikeLikeEntity* this) {
    if (super->timer == 2 && this->stolenItem != 0xff) {
        SetEntityPriority(super, PRIO_NO_BLOCK);
        LikeLike_ReturnStolenItem(this->stolenItem);
    }
    GenericDeath(super);
}

void LikeLike_OnGrabbed(LikeLikeEntity* this) {
}

void LikeLike_Init(LikeLikeEntity* this) {
    sub_0804A720(super);

    switch (super->type) {
        case 0:
            super->action = 3;
            super->spriteSettings.draw = 0;
            COLLISION_OFF(super);
            super->timer = 0;
            break;
        case 1:
            super->action = 1;
            super->spriteSettings.draw = 1;
            super->timer = 8;
            InitializeAnimation(super, 1);
            break;
        case 2:
            super->action = 1;
            super->spriteSettings.draw = 0;
            super->timer = 0;
            super->hitType = 1;
            InitializeAnimation(super, 0);
            break;
    }

    super->direction = 0;
    this->field_0x82 = 0;
    super->animationState = 0;
    this->prevSpritePriority = 0;
    this->stolenItem = 0xff;
}

void sub_08027EFC(LikeLikeEntity* this) {
    if (super->hitType == 1)
        return;

    if (sub_08049FDC(super, 1)) {
        if (!sub_08049FA0(super) && (Random() & 0x30)) {
            super->direction = sub_08049EE4(super);
        } else {
            super->direction = this->field_0x82;
        }

        if (--super->timer == 0) {
            super->direction = sub_08049F84(super, 1);
            this->field_0x82 = super->direction;
            super->timer = 8;
        }
        ProcessMovement0(super);
        GetNextFrame(super);
    } else {
        super->action = 6;
        COLLISION_OFF(super);
        InitializeAnimation(super, 2);
    }
}

void nullsub_12(LikeLikeEntity* this) {
}

void sub_08027F84(LikeLikeEntity* this) {
    if (sub_08049FDC(super, 1)) {
        super->action = 5;
        super->spriteSettings.draw = 1;
        InitializeAnimation(super, 0);
        CreateDust(super);
    }
}

void sub_08027FB4(LikeLikeEntity* this) {
    if (--super->timer == 0) {
        super->action = 1;
        super->timer = 1;
        super->flags2 |= 1;
    }
    GetNextFrame(super);
}

void sub_08027FE0(LikeLikeEntity* this) {
    GetNextFrame(super);
    if (super->frame & 1) {
        super->action = 1;
        COLLISION_ON(super);
        super->direction = sub_08049F84(super, 1);
        super->timer = 8;
        super->spritePriority.b1 = 1;
        InitializeAnimation(super, 1);
    }
}

void sub_0802802C(LikeLikeEntity* this) {
    GetNextFrame(super);
    if (super->frame & 1) {
        super->action = 3;
        super->spriteSettings.draw = 0;
        super->direction = 0;
        super->timer = 0;
        CreateDust(super);
    }
}

void sub_0802805C(LikeLikeEntity* this) {
    u8* tmp;

    UpdateAnimationVariableFrames(super, 2);

    if (sub_0807953C()) {
        u32 tmp2 = Random();
        u32 tmp3 = super->subtimer + 1;
        tmp3 += (tmp2 & 1);
        super->subtimer = tmp3;
    }

    if (super->subtimer >= 0x19 || gSave.stats.health == 0) {
        LikeLike_ReleasePlayer(this);
    } else {
        ResetActiveItems();
        gPlayerState.mobility |= 0x80;
        PositionRelative(super, &gPlayerEntity.base, 0, Q_16_16(1.0));

        tmp = GetSpriteSubEntryOffsetDataPointer((u16)super->spriteIndex, super->frameIndex);
        gPlayerEntity.base.spriteOffsetX = tmp[0];
        gPlayerEntity.base.spriteOffsetY = tmp[1];
        gPlayerEntity.base.spritePriority.b1 = 0;

        if (--super->timer == 0) {
            sub_080281A0(this);
        }

        if ((super->timer & 3) == 0) {
            EnqueueSFX(SFX_PLACE_OBJ);
        }
    }
}

void LikeLike_ReleasePlayer(LikeLikeEntity* this) {
// This matches but ugly
#ifndef NON_MATCHING
    register u32 tmp asm("r3");
#else
    u32 tmp;
#endif
    gPlayerState.jump_status = 0x41;
    gPlayerState.field_0xa = 0;
    gPlayerState.flags &= ~PL_CAPTURED;
    gPlayerEntity.base.flags |= ENT_COLLIDE;
    gPlayerEntity.base.zVelocity = Q_16_16(1.5);
    gPlayerEntity.base.iframes = -60;
    tmp = 0;
    gPlayerEntity.base.direction = Direction8FromAnimationState(gPlayerEntity.base.animationState);
    gPlayerEntity.base.spritePriority.b1 = this->prevSpritePriority;
    gPlayerEntity.base.z.HALF.HI = gPlayerEntity.base.spriteOffsetY;
    gPlayerEntity.base.spriteOffsetY = tmp;
    super->action = 4;
    super->timer = 80;
    super->subtimer = tmp;
    super->flags2 |= 2;
    if (super->iframes == 0) {
        super->iframes = -18;
    }
}

void sub_080281A0(LikeLikeEntity* this) {
    super->subtimer = 25;
    if (LikeLike_StealItem(ITEM_MIRROR_SHIELD)) {
        this->stolenItem = ITEM_MIRROR_SHIELD;
        MessageFromTarget(TEXT_INDEX(TEXT_ITEM_GET, 0x78));
    } else if (LikeLike_StealItem(ITEM_SHIELD)) {
        this->stolenItem = ITEM_SHIELD;
        MessageFromTarget(TEXT_INDEX(TEXT_ITEM_GET, 0x78));
    } else {
        ModHealth(-1);
    }
}

bool32 LikeLike_StealItem(u32 item) {
    bool32 ret = FALSE;
    if (GetInventoryValue(item) == 1) {
        if (ItemIsShield(gSave.stats.equipped[SLOT_A])) {
            gSave.stats.equipped[SLOT_A] = ITEM_NONE;
        }

        if (ItemIsShield(gSave.stats.equipped[SLOT_B])) {
            gSave.stats.equipped[SLOT_B] = ITEM_NONE;
        }

        SetInventoryValue(item, 0);
        ret = TRUE;
    }

    return ret;
}

void LikeLike_ReturnStolenItem(u32 item) {
#ifdef EU
    CreateItemEntity(item, 0, 1);
#else
    InitItemGetSequence(item, 0, 1);
#endif
    MessageFromTarget(TEXT_INDEX(TEXT_ITEM_GET, 0x79));
}

void (*const LikeLike_Functions[])(Entity*) = {
    (EntityActionPtr)LikeLike_OnTick,
    (EntityActionPtr)LikeLike_OnCollision,
    GenericKnockback,
    (EntityActionPtr)LikeLike_OnDeath,
    GenericConfused,
    (EntityActionPtr)LikeLike_OnGrabbed,
};

void (*const gUnk_080CC714[])(LikeLikeEntity*) = {
    LikeLike_Init, sub_08027EFC, nullsub_12, sub_08027F84, sub_08027FB4, sub_08027FE0, sub_0802802C, sub_0802805C,
};
