#include "d/a/obj/d_a_obj_flying_clawshot_target.h"

#include "common.h"
#include "d/a/d_a_player.h"
#include "d/a/obj/d_a_obj_base.h"
#include "d/col/c/c_cc_d.h"
#include "d/col/cc/d_cc_d.h"
#include "d/col/cc/d_cc_s.h"
#include "f/f_base.h"
#include "m/m_mtx.h"
#include "m/m_quat.h"
#include "m/m_vec.h"
#include "nw4r/g3d/res/g3d_resfile.h"
#include "nw4r/g3d/res/g3d_resmdl.h"
#include "rvl/MTX/mtxvec.h"

SPECIAL_ACTOR_PROFILE(
    OBJ_FLYING_CLAWSHOT_TARGET, dAcOFlyingClawshotTarget_c, fProfile::OBJ_FLYING_CLAWSHOT_TARGET, 0x142, 0, 2
);

bool dAcOFlyingClawshotTarget_c::createHeap() {
    void *data = getOarcResFile("BirdObjD3_S");

    if (!data) {
        return false;
    }

    nw4r::g3d::ResFile file(data);
    if (!file.IsValid()) {
        return false;
    }
    nw4r::g3d::ResMdl mdl = file.GetResMdl("BirdObjD3_S");
    if (!mdl.IsValid()) {
        return false;
    }

    return mMdl.create(mdl, &mAllocator, 0x120, 1, nullptr);
}

// clang-format off
const cCcD_SrcGObj dAcOFlyingClawshotTarget_c::sColSrc = {
  /* mObjAt */ {0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0},
  /* mObjTg */ {~(AT_TYPE_BUGNET | AT_TYPE_BEETLE | AT_TYPE_GLITTERING_SPORES | AT_TYPE_0x8000 | AT_TYPE_WIND), 0x1080111, {0, 6, 0x407}, 0, 0},
  /* mObjCo */ {0x0}
};
// clang-format on

int dAcOFlyingClawshotTarget_c::actorCreate() {
    CREATE_ALLOCATOR_UNCHECKED(dAcOFlyingClawshotTarget_c);

    mMdl.setPriorityDraw(0x7F, 0x7F);
    mWorldMtx.transS(mVec3_c::Zero);
    mMdl.setLocalMtx(mWorldMtx);
    mMdl.calc(true);
    mMdl.getNodeWorldMtxMultVecZero(mMdl.getNodeID("Mark_point"), mMarkPoint);

    mStts.SetRank(0xC);
    dCcD_SrcSph src = {sColSrc, 80.f};

    mSph.Set(src);
    mSph.SetStts(mStts);
    mSph.SetC(mPosition);
    mState = 0;

    mVec3_c min, max;
    mMdl.getBounds(&min, &max);
    mBoundingBox.Set(min, max);

    return SUCCEEDED;
}

int dAcOFlyingClawshotTarget_c::actorPostCreate() {
    mVec3_c v = mVec3_c::Ez;
    v.rotX(mRotation.x);
    v.rotY(mRotation.y);
    mVec3_c diff = dAcPy_c::LINK->mPosition - mPosition;
    diff.normalize();
    if (!mToLink.Set(v, diff)) {
        mToLink.set(1.f, 0.f, 0.f, 0.f);
    }
    return SUCCEEDED;
}

int dAcOFlyingClawshotTarget_c::actorExecute() {
    dAcPy_c *player = dAcPy_c::LINK;

    mVec3_c markPoint;
    MTXMultVec(mWorldMtx, mMarkPoint, markPoint);

    f32 dist_to = markPoint.squareDistance(player->mPosition);

    if (checkObjectProperty(OBJ_PROP_0x4)) {
        player->vt_0x0DC(this, mMarkPoint);
    }
    if (checkObjectProperty(OBJ_PROP_0x4) && dist_to < 2500.f &&
        (player->checkActionFlagsCont(0x10000000) || player->checkActionFlagsCont(0x20000000))) {
        static mVec3_c vec = -mVec3_c::Ey;
        mVec3_c v2;

        v2.copyFrom(mToLink.rotateVector(mVec3_c::Ez));
        f32 f = 0.16f;

        mQuat_c q;
        if (!q.fn_802F2450(v2, vec, f)) {
            q.set(1.f, 0.f, 0.f, 0.f);
        }

        mToLink = q * mToLink;

    } else {
        mVec3_c vec = player->mPosition - mPosition;
        vec.normalize();

        mVec3_c v2;
        v2.copyFrom(mToLink.rotateVector(mVec3_c::Ez));
        f32 f = 0.1f;

        mQuat_c q;
        if (!q.fn_802F2450(v2, vec, f)) {
            q.set(1.f, 0.f, 0.f, 0.f);
        }

        mToLink = q * mToLink;
    }

    switch (mState) {
        case 0: {
            if (checkObjectProperty(OBJ_PROP_0x4)) {
                if (player->checkActionFlagsCont(0x10000000) || player->checkActionFlagsCont(0x20000000)) {
                    mState = 2;
                } else {
                    mState = 1;
                }
            }
        } break;
        case 1: {
            if (checkObjectProperty(OBJ_PROP_0x4)) {
                if (player->checkActionFlagsCont(0x10000000) || player->checkActionFlagsCont(0x20000000)) {
                    mState = 2;
                }
            } else {
                mState = 0;
            }
        } break;
        case 2: {
            if (!checkObjectProperty(OBJ_PROP_0x4)) {
                mState = 0;
            }
        } break;
    }

    mMtx_c mtx;
    updateMatrix();
    mtx.fromQuat(mToLink);
    mWorldMtx += mtx;
    mMdl.setLocalMtx(mWorldMtx);
    mMdl.calc(false);
    mSph.SetC(mPosition);
    dCcS::GetInstance()->Set(&mSph);

    return SUCCEEDED;
}

int dAcOFlyingClawshotTarget_c::draw() {
    drawModelType1(&mMdl);

    return SUCCEEDED;
}
