#define NENT_DEPRECATED
#include "entity.h"
#include "flags.h"
#include "save.h"
#include "room.h"
#include "asm.h"
#include "sound.h"
#include "common.h"
#include "object.h"

typedef struct {
    Entity base;
    const u8* unk68;
} BigBarrelEntity;

void sub_08088A68(BigBarrelEntity*);
void sub_08088C9C(BigBarrelEntity*);
void sub_08088DB4(BigBarrelEntity*);
void sub_08088E74(BigBarrelEntity*);
void sub_08088F20(BigBarrelEntity*);
void sub_08088BE0(BigBarrelEntity*);
void sub_08089094(BigBarrelEntity*);
void sub_080890EC(BigBarrelEntity*, const s16*, s32);

Entity* sub_08088C78(BigBarrelEntity*, u32, u32, u32);

extern bool32 sub_0806FB38(Entity*);
extern void sub_0806FB00(Entity*, u32, u32, u32);

const s8 gUnk_08120C1C[] = { 3, 0, 2, 0, 2, 0, 1, 0, -1 };
const s8 gUnk_08120C25[] = { 5, 0, 4, 0, 4, 0, 2, 0, -1 };
const s8 gUnk_08120C2E[] = { 3, 0, -1, 0, 0, 0 };

void BigBarrel(Entity* this) {
    static void (*const typeFuncs[])(BigBarrelEntity*) = {
        sub_08088A68, sub_08088C9C, sub_08088DB4, sub_08088E74, sub_08088F20,
    };
    typeFuncs[this->type]((BigBarrelEntity*)this);
}

void sub_08088A68(BigBarrelEntity* this) {
    u32 uVar3;
    const u8* pcVar3;

    if (super->action == 0) {
        super->action = 1;
        super->spriteSettings.draw = 3;
        super->updatePriority = 3;
        if (CheckGlobalFlag(0x17)) {
            super->frameIndex = gSave.unk7 + 1;
        } else {
            super->frameIndex = gSave.unk7;
        }
        sub_08088BE0(this);
        if (CheckPlayerInRegion(super->x.HALF.HI - gRoomControls.origin_x, super->y.HALF.HI - gRoomControls.origin_y,
                                0x80, 0x60)) {
            gRoomVars.animFlags |= 4;
        }
    } else {
        if (gRoomVars.animFlags & 1) {
            gRoomVars.animFlags &= ~1;
            super->actionDelay = 1;
            this->unk68 = gUnk_08120C1C;
            SoundReq(SFX_BARREL_ENTER);
        }
        if (gRoomVars.animFlags & 2) {
            gRoomVars.animFlags &= ~2;
            super->actionDelay = 1;
            this->unk68 = gUnk_08120C25;
            SoundReq(SFX_BARREL_RELEASE);
        }
        if (gRoomVars.animFlags & 4) {
            gRoomVars.animFlags &= ~4;
            super->actionDelay = 1;
            this->unk68 = gUnk_08120C2E;
            SoundReq(SFX_BARREL_ENTER);
        }
        if (super->actionDelay) {
            if (super->actionDelay-- == 1) {
                pcVar3 = this->unk68;
                uVar3 = pcVar3[0];
                *(u8*)&super->spriteOffsetY = uVar3;
                pcVar3++;
                if (*pcVar3 != 0xff) {
                    super->actionDelay = 8;
                    this->unk68 = pcVar3;
                } else {
                    super->spriteOffsetY = 0;
                }
            }
        }
    }
    super->spritePriority.b0 = 1;
    if (CheckPlayerProximity(super->x.HALF.HI - 0x50, super->y.HALF.HI - 0x50, 0xa0, 0x30)) {
        super->spritePriority.b0 = 5;
    }
    if (CheckPlayerProximity(super->x.HALF.HI - 0x50, super->y.HALF.HI + 0x30, 0xa0, 0x30)) {
        super->spritePriority.b0 = 5;
    }
}

void sub_08088BE0(BigBarrelEntity* this) {
    Entity* ent;

    if (CheckLocalFlag(0x15) == 0) {
        sub_08088C78(this, 2, 0, 0xffffff88);
        ent = sub_08088C78(this, 4, 0x15, 0);
        if (ent) {
            ent->x.HALF.HI = gRoomControls.origin_x + 0x48;
            ent->y.HALF.HI = gRoomControls.origin_y + 200;
        }
    }

    if (CheckLocalFlag(0x16) == 0) {
        sub_08088C78(this, 2, 1, 0x78);
        ent = sub_08088C78(this, 4, 0x16, 0);
        if (ent) {
            ent->x.HALF.HI = gRoomControls.origin_x + 0x188;
            ent->y.HALF.HI = gRoomControls.origin_y + 200;
        }
    }
    sub_08088C78(this, 1, 0, 0xffffff88);
    sub_08088C78(this, 1, 1, 0x78);
}

Entity* sub_08088C78(BigBarrelEntity* this, u32 type, u32 type2, u32 xOffset) {
    Entity* pEVar1;

    pEVar1 = CreateObject(BIG_BARREL, type, type2);
    if (pEVar1) {
        pEVar1->x.HALF.HI = super->x.HALF.HI + xOffset;
        pEVar1->y.HALF.HI = super->y.HALF.HI;
        pEVar1->parent = super;
    }
    return pEVar1;
}

void sub_08088C9C(BigBarrelEntity* this) {
    static const u8 gUnk_08120C48[] = { 2, 3, 4, 5, 6, 7, 7, 7 };
    static const s8 gUnk_08120C50[] = { 8, -8 };
    u32 localFlag;
    s32 x;

    super->spritePriority.b0 = gUnk_08120C48[super->parent->spritePriority.b0];
    super->spriteOffsetY = super->parent->spriteOffsetY / 2;
    switch (super->action) {
        case 0:
            super->action = 1;
            super->spriteSettings.draw = 1;
            super->frameIndex = super->type2 + 4;
            super->updatePriority = 3;
            if (super->type2 == 0) {
                localFlag = 21;
            } else {
                localFlag = 22;
            }
            super->field_0xf = localFlag;
            if (CheckLocalFlag(super->field_0xf) == 0) {
                return;
            }

            super->x.HALF_U.HI += gUnk_08120C50[super->type2];
            super->action = 4;
            break;
        case 1:
            if (CheckLocalFlag(super->field_0xf) == 0) {
                return;
            }
            super->action = 2;
            break;
        case 2:
            if ((gRoomVars.animFlags & 0x20) == 0) {
                return;
            }
            gRoomVars.animFlags &= ~0x20;
            super->action = 3;
            super->subAction = 4;
            super->actionDelay = 1;
        case 3:
            if (--super->actionDelay) {
                return;
            }
            super->actionDelay = 8;
            x = super->x.HALF.HI;
            if (super->type2) {
                super->x.HALF.HI = x - 2;
            } else {
                super->x.HALF.HI = x + 2;
            }
            if (--super->subAction) {
                return;
            }
            super->action = 4;
            break;
    }
}

void sub_08088DB4(BigBarrelEntity* this) {
    switch (super->action) {
        case 0:
            super->action = 1;
            super->spriteSettings.draw = 1;
            super->frameIndex = super->type2 * 4 + 6;
            super->collisionLayer = 2;
            SetDefaultPriority(super, 3);
            super->type2 = super->type2 == 0 ? 0x15 : 0x16;
            UpdateSpriteForCollisionLayer(super);
            break;
        case 1:
            if (CheckLocalFlag(super->type2)) {
                super->action++;
                super->actionDelay = 10;
            }
            break;
        case 2:
        case 3:
        case 4:
            if ((gRoomVars.animFlags & 8) == 0) {
                return;
            }
            if (--super->actionDelay) {
                return;
            }
            super->actionDelay = 0x1e;
            super->frameIndex++;
            super->action++;
            break;
        default:
            if (--super->actionDelay == 0) {
                gRoomVars.animFlags &= ~0x8;
                DeleteEntity(super);
            }
            break;
    }
}

void sub_08088E74(BigBarrelEntity* this) {
    static const s8 gUnk_08120C52[] = { -2, 0, 2, 0 };
    Entity* ent;

    if (super->action == 0) {
        super->action = 1;
        super->collisionLayer = 2;
        gRoomVars.animFlags |= 8;
    }
    if (sub_0806FB38(super)) {
        gRoomVars.animFlags |= 0x10;
        DeleteEntity(super);
    } else {
        if ((gRoomTransition.frameCount & 7U) == 0) {
            ent = CreateObjectWithParent(super, OBJECT_2A, 0, 0x1e);
            if (ent) {
                ent->updatePriority = 3;
                ent->spriteRendering.b3 = 0;
                ent->spritePriority.b0 = 0;
                ent->spriteOrientation.flipY = 0;
                ent->y.HALF.HI += gUnk_08120C52[Random() & 3];
            }
        }
    }
}

void sub_08088F20(BigBarrelEntity* this) {
    Entity* pEVar3;

    switch (super->action) {
        case 0:
            super->action = 1;
            super->updatePriority = 3;
            if (CheckLocalFlag(super->type2) == 0) {
                return;
            }
            DeleteEntity(super);
            break;
        case 1:
            if (CheckLocalFlag(super->type2) == 0) {
                return;
            }
            super->action = 2;
            super->actionDelay = 30;
            RequestPriorityDuration(super, 0x10e);
            pEVar3 = CreateObject(OBJECT_2A, 1, 0);
            if (pEVar3 != NULL) {
                pEVar3->updatePriority = 3;
                pEVar3->x.HALF.HI = super->x.HALF.HI;
                pEVar3->y.HALF.HI = super->y.HALF.HI;
                pEVar3->collisionLayer = 2;
                pEVar3->spritePriority.b0 = 2;
            }
            SetTileType(0x76, COORD_TO_TILE(super), 2);
            break;
        case 2:
            if (--super->actionDelay) {
                return;
            }
            sub_08089094(this);
            super->action = 3;
            break;
        case 3:
            if ((gRoomVars.animFlags & 0x10) == 0) {
                return;
            }
            super->action = 4;
            super->actionDelay = 0x78;
            break;
        default:
            if (--super->actionDelay == 0x5a) {
                if (CheckLocalFlags(0x15, 2)) {
                    gRoomVars.animFlags |= 2;
                } else {
                    gRoomVars.animFlags |= 1;
                }
                gRoomVars.animFlags |= 0x20;
            }
            if (super->actionDelay == 0) {
                gRoomVars.animFlags &= ~0x10;
                if (CheckLocalFlags(0x15, 2)) {
                    RequestPriorityDuration(super, 0x3c);
                    SoundReq(SFX_SECRET);
                }
                DeleteEntity(super);
            }
            break;
    }
}

void sub_08089094(BigBarrelEntity* this) {
    static const s16 gUnk_08120C56[] = { 0x58, -0x30, 0x58, 0x30 };
    static const s16 gUnk_08120C5E[] = { -0x58, -0x30, -0x58, 0x30 };

    if (super->x.HALF.HI - gRoomControls.origin_x < 0x100) {
        sub_080890EC(this, gUnk_08120C56, -8);
        sub_080890EC(this, gUnk_08120C56 + 2, 4);
    } else {
        sub_080890EC(this, gUnk_08120C5E, -8);
        sub_080890EC(this, gUnk_08120C5E + 2, 4);
    }
}

void sub_080890EC(BigBarrelEntity* this, const s16* offsets, s32 yOffset) {
    Entity* pEVar1 = CreateObject(BIG_BARREL, 3, 0);
    if (pEVar1) {
        SetDefaultPriority(pEVar1, 3);
        pEVar1->x.HALF.HI = super->x.HALF.HI;
        pEVar1->y.HALF.HI = super->y.HALF.HI + yOffset;
        pEVar1->parent = super;
        sub_0806FB00(pEVar1, pEVar1->x.HALF.HI + offsets[0], pEVar1->y.HALF.HI + offsets[1], 0x5a);
    }
}
