#include "Actor/ActorRupee.hpp"
#include "Item/ItemManager.hpp"
#include "Map/MapManager.hpp"
#include "Player/PlayerLinkBase.hpp"
#include "System/Random.hpp"
#include "Unknown/UnkStruct_020eec9c.hpp"

extern "C" {
void func_0202bc38(unk32 param_1, Vec3p *param_2, u32 param_3, Actor_UnkStruct_012 *param_4, bool);
void func_ov005_02102c2c(u32 *param_1, int param_2, Vec3p *param_3, int param_4, int param_5, u32 param_6, int param_7,
                         char param_8, char param_9, char param_10);
}
u16 GetRupeeValue(RupeeId id);

static char *gShipParts[8] = {"anc", "bow", "hul", "can", "dco", "pdl", "fnl", "brg"};

extern u32 *data_ov014_021589d8;
extern u32 data_ov000_020e9370[];
extern u32 **data_027e0fe0[];

ActorType ActorRupee::gType = ActorType(ActorTypeId_Rupee, (ActorCreateFunc) ActorRupee::Create, NULL);

ARM ActorRupee *ActorRupee::Create() {
    ActorRupee *newRupee = new(*data_027e0fe0[0], 4) ActorRupee();
    return newRupee;
}

static const ActorType_UnkClass data_ov014_021589f4 = ActorType_UnkClass(FLOAT_TO_Q21(0.4662), FLOAT_TO_Q19(0.4661));

ARM ActorRupee::ActorRupee() {
    mRupeeId = 8;
    mUnk_15c = 0;
}

ARM bool ActorRupee::Init() {
    RupeeId rupeeId        = (RupeeId) mUnk_020.mUnk_00[0];
    mRupeeId               = rupeeId;
    s32 iVar1              = (func_ov14_0213b70c(rupeeId) ? data_ov014_021589f4.mUnk_4 : 0xaa8) >> 1;
    mHitbox.pos.x          = 0;
    mHitbox.pos.y          = iVar1;
    mHitbox.pos.z          = 0;
    mHitbox.size           = iVar1;
    mUnk_08c.pos.x         = mHitbox.pos.x;
    mUnk_08c.pos.y         = mHitbox.pos.y;
    mUnk_08c.pos.z         = mHitbox.pos.z;
    mUnk_08c.size          = mHitbox.size;
    mUnk_0a4.mUnk_04.pos.x = 0;
    mUnk_0a4.mUnk_04.pos.y = iVar1;
    mUnk_0a4.mUnk_04.pos.z = 0;
    mUnk_0a4.mUnk_04.size  = iVar1 + 0x1000;
    mUnk_09c.mUnk_0        = mUnk_09c.mUnk_0 & ~0xb0;
    mUnk_09c.mUnk_3        = 1;
    mMaxFall               = mUnk_08c.size + -1;
    if (mUnk_03c >= 0) {
        this->func_ov14_0213b204(1);
    } else {
        switch (mUnk_144) {
            case 0:
                mVel.x = 0;
                mVel.y = 0;
                mVel.z = 0;
                this->func_ov14_0213b204(0);
                break;
            case 1:
                mVel.x = gRandom.Next(FLOAT_TO_Q20(-0.0666), FLOAT_TO_Q20(0.0666));
                mVel.y = gRandom.Next(FLOAT_TO_Q20(0.3333), FLOAT_TO_Q20(0.5333));
                mVel.z = gRandom.Next(FLOAT_TO_Q20(-0.0666), FLOAT_TO_Q20(0.0666));
                this->func_ov14_0213b204(0);
                break;
            case 2:
                mVel.x = 0;
                mVel.y = FLOAT_TO_Q20(0.5);
                mVel.z = 0;
                this->func_ov14_0213b204(0);
                break;
            case 3:
                this->func_ov14_0213b204(5);
        }
    }
    return true;
}

ARM bool ActorRupee::vfunc_60() {
    return func_ov14_0213b70c(mRupeeId);
}

ARM void ActorRupee::vfunc_64() {}

ARM void ActorRupee::Move() {
    s32 size;

    ApplyGravity();
    Vec3p_Add(&mPos, &mVel, &mPos); // Vec3p::Add()
    mUnk_09c.mUnk_3 = 1;
    size = mMaxFall = mUnk_08c.size - 1;

    size += mUnk_014.y;
    if (size < mPos.y) {
        mUnk_09c.mUnk_0 = 0x49;
    } else {
        mUnk_09c.mUnk_0 = 0xcb;
    }

    if (this->func_01fffd04(0)) {
        mVel.x = 0;
        mVel.z = 0;
    }
}

ARM ItemId ActorRupee::GetRupeeCutsceneItemId() {
    switch (mRupeeId) {
        case RupeeId_Green:
            return ItemId_None;

        case RupeeId_Blue:
            return ItemId_None;

        case RupeeId_Red:
            return ItemId_None;

        case RupeeId_BigGreen:
            return ItemId_BigGreenRupee;

        case RupeeId_BigRed:
            return ItemId_BigRedRupee;

        case RupeeId_Gold:
            return ItemId_GoldRupee;

        case RupeeId_Rupoor10:
            return ItemId_Rupoor10;

        case RupeeId_Rupoor50:
            return ItemId_Rupoor50;

        default:
            break;
    }

    return ItemId_None;
}

ARM void ActorRupee::func_ov14_0213b204(unk32 param1) {
    switch (param1) {
        case 0:
            mVisible = true;
            break;
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
            mVel.x = 0;
            mVel.y = 0;
            mVel.z = 0;
            break;
    }

    mActiveFrames = 0;
    mUnk_130      = param1;
}

ARM void ActorRupee::Update(bool param1) {
    ItemId cutsceneItemId;
    s32 uVar3;
    Vec3p local_1c;
    u32 local_20;
    u16 rupeeValue;

    mPrevPos = mPos;
    IncreaseActiveFrames();

    if ((mUnk_130 != 3) && (++mUnk_15c >= 6) && CollidesWithPlayer(PlayerCollide_PickupFlags)) {
        cutsceneItemId = GetRupeeCutsceneItemId();

        if (cutsceneItemId >= 0) {
            if (gPlayerLink->PlayItemCutscene(cutsceneItemId)) {
                Kill();
            } else {
                func_ov14_0213b204(3);
            }
        } else {
            ItemManager *pItemMgr = gItemManager;
            rupeeValue            = GetRupeeValue(mRupeeId);
            pItemMgr->GiveRupees(rupeeValue, false);
            uVar3 = -1;

            switch (mRupeeId) {
                case RupeeId_Green:
                    uVar3 = 0xfa;
                    break;
                case RupeeId_Blue:
                    uVar3 = 0xfb;
                    break;
                case RupeeId_Red:
                    uVar3 = 0xfc;
                    break;
                default:
                    break;
            }

            data_ov000_020eec9c.func_ov000_020d7ad4(uVar3);
            Kill();
        }
    }

    if (!(mUnk_130 != 0 && mUnk_130 != 1 && mUnk_130 != 2)) {
        if (func_ov00_020c2c0c()) {
            func_ov14_0213b204(4);
        } else if (func_ov00_020c2d54()) {
            func_ov14_0213b204(5);
        }
    }

    switch (mUnk_130) {
        case 0:
            Move();
            if (mTouchingFloor) {
                local_1c = mPos;
                MapManager::func_ov00_02083fb0(&local_20, gMapManager, &local_1c);
                if (((local_20 >> 5) & 3) == 2) {
                    Kill();
                } else {
                    func_ov14_0213b204(1);
                }
            }
            break;
        case 3: {
            PlayerLinkBase *pLink = gPlayerLink;
            if (pLink->PlayItemCutscene(GetRupeeCutsceneItemId())) {
                Kill();
            }
        } break;
        case 1:
            if (param1) {
                mActiveFrames = 0;
            }
            if ((mUnk_03c < 0) && (mActiveFrames >= 180)) {
                func_ov14_0213b204(2);
            }
            break;
        case 2:
            if (param1) {
                mActiveFrames = 0;
            }
            if (mActiveFrames >= 60) {
                Kill();
            }
            break;
        case 4:
            if (!func_ov00_020c2c70()) {
                func_ov14_0213b204(1);
            }
            break;
        case 5:
            if (!func_ov00_020c2de4()) {
                func_ov14_0213b204(1);
            }
            break;
        default:
            break;
    }

    KillInBounds();
}

ARM void ActorRupee::vfunc_14(u32 param1) {
    if (func_ov00_020c313c(param1)) {
        Update(false);
    }
    mUnk_0a4.func_ov000_0207a1c8(param1, &mPos);
}

ARM void ActorRupee::vfunc_18(u32 param1) {
    if (func_ov00_020c313c(param1)) {
        Update(true);
    }
    mUnk_0a4.func_ov000_0207a1c8(param1, &mPos);
}

#define VFUNC20_COND (param1 ? mUnk_0a4.mUnk_01 : mUnk_0a4.mUnk_00)
ARM void ActorRupee::vfunc_20(bool param1) {
    if (VFUNC20_COND && !(mUnk_130 == 2 && mActiveFrames % 8 < 4) && VFUNC20_COND) {
        func_ov14_0213b5f4(mRupeeId, param1, &mPos, true);
    }
}

ARM void ActorRupee::func_ov14_0213b5f4(RupeeId id, unk32 param2, Vec3p *param3, bool param4) {
    Actor_UnkStruct_012 unk_class;
    static const u32 data_ov014_02153e28[] = {
        // sRupeePalettes
        0x9, // RupeeId_Green
        0xA, // RupeeId_Blue
        0x8, // RupeeId_Red
        0x9, // RupeeId_BigGreen
        0x8, // RupeeId_BigRed
        0xB, // RupeeId_Gold
        0xC, // RupeeId_Rupoor10
        0xC, // RupeeId_Rupoor50
    };

    func_ov14_0213b6a4(id, &unk_class);
    func_0202bc38(param2, param3, data_ov014_02153e28[id], &unk_class, 0);

    if (param4) {
        u32 var = func_ov14_0213b70c(id) ? 0x4cd : 0x400;
        func_ov005_02102c2c(&data_ov000_020e9370[0], 0, param3, var, var, 0, 0x1f, 0, 1, 1);
    }
}

ARM void ActorRupee::func_ov14_0213b6a4(RupeeId id, Actor_UnkStruct_012 *param2) {
    param2->mUnk_04 = 3;

    if (func_ov14_0213b70c(id)) {
        param2->mUnk_08 = 2;
        param2->mUnk_0c = 2;
        param2->mUnk_14 = data_ov014_021589f4.mUnk_0;
        param2->mUnk_18 = data_ov014_021589f4.mUnk_4;
    } else {
        param2->mUnk_08 = 2;
        param2->mUnk_0c = 2;
        param2->mUnk_14 = FLOAT_TO_Q21(0.333);
        param2->mUnk_18 = FLOAT_TO_Q19(0.333);
    }
}

ARM bool ActorRupee::func_ov14_0213b70c(RupeeId id) {
    switch (id) {
        case RupeeId_BigGreen:
        case RupeeId_BigRed:
        case RupeeId_Gold:
        case RupeeId_Rupoor50:
            return true;

        default:
            break;
    }

    return false;
}

ActorRupee::~ActorRupee() {}
