#include "d/a/d_a_bird_base.h"

#include "c/c_math.h"
#include "common.h"
#include "d/col/bg/d_bg_s.h"
#include "d/col/bg/d_bg_s_lin_chk.h"
#include "m/m3d/m_fanm.h"
#include "m/m_mtx.h"
#include "m/m_vec.h"

void dAcBirdBase_c::callback_c::timingB(u32, nw4r::g3d::WorldMtxManip *, nw4r::g3d::ResMdl) {
    // TODO
}

int dAcBirdBase_c::doDelete() {
    return SUCCEEDED;
}

int dAcBirdBase_c::draw() {
    drawModelType1(&mMdl.getModel());
    return SUCCEEDED;
}

void dAcBirdBase_c::updateMatrixBird() {
    mWorldMtx.transS(mPosition);
    mWorldMtx.concat(field_0xF80);
    mWorldMtx.ZrotM(mRotation.z);
    mWorldMtx.scaleM(field_0xF50.x, field_0xF50.y, field_0xF50.z);
    mMdl.getModel().setLocalMtx(mWorldMtx);
    mMdl.getModel().calc(false);
}

bool dAcBirdBase_c::changeBirdAction(const char *animName, s32 action, m3d::playMode_e playMode, f32 blend) {
    void *data;
    if (action < BIRD_ACTION_HOVER) {
        data = getOarcResFile(getAnmArcNameBase());
    } else if (action < BIRD_ACTION_BASE_MAX) {
        data = getOarcResFile(getAnmArcNameLink());
    } else {
        data = getOarcResFile(getAnmArcNameSpecial());
    }
    mMdl.setAnmFile(data);
    bool ret = false;
    if (mBirdAction != action) {
        mMdl.setAnm(animName, playMode, blend);
        mBirdAction = action;
        ret = true;
    }
    return ret;
}

void dAcBirdBase_c::executeBirdAction() {
    if (mBirdAction == BIRD_ACTION_GLIDE) {
        if (--mBirdActionTimer <= 0) {
            changeBirdAction("Flap", BIRD_ACTION_FLAP, m3d::PLAY_MODE_4, 5.0f);
            mBirdActionTimer = cM::rndInt(100) + 100;
        } else if (field_0xF5C.y < -0.3f) {
            changeBirdAction("SwitchToDive", BIRD_ACTION_SWITCH_DIVE, m3d::PLAY_MODE_4, 5.0f);
        }
    } else if (mBirdAction == BIRD_ACTION_GLIDE_DIVE) {
        if (field_0xF5C.y >= -0.2f) {
            changeBirdAction("SwitchToDive", BIRD_ACTION_SWITCH_DIVE, m3d::PLAY_MODE_3, 5.0f);
        }
    } else if (mBirdAction == BIRD_ACTION_SWITCH_DIVE) {
        if (mMdl.getAnm().isStop()) {
            if (mMdl.getAnm().getPlayMode() == m3d::PLAY_MODE_3) {
                changeBirdAction("Glide", BIRD_ACTION_GLIDE, m3d::PLAY_MODE_4, 5.0f);
            } else {
                changeBirdAction("GlideDive", BIRD_ACTION_GLIDE_DIVE, m3d::PLAY_MODE_4, 5.0f);
            }
        } else if (field_0xF5C.y >= -0.15f) {
            changeBirdAction("SwitchToDive", BIRD_ACTION_SWITCH_DIVE, m3d::PLAY_MODE_3, 5.0f);
        }
    } else {
        if ((mMdl.getAnm().isStop() && mBirdAction == BIRD_ACTION_FLAP) ||
            (mMdl.getAnm().isStop() && mBirdAction == BIRD_ACTION_DAMAGE) ||
            (mMdl.getAnm().isStop() && mBirdAction == BIRD_ACTION_HOVER)) {
            changeBirdAction("Glide", BIRD_ACTION_GLIDE, m3d::PLAY_MODE_4, 5.0f);
            mBirdActionTimer = cM::rndInt(100) + 100;
        }
    }
}

bool dAcBirdBase_c::chkWallGndRoofHit() {
    mVec3_c tmp;
    tmp.set(mPosition); // unused

    if (--mChkWallGndRoofTimer <= 0) {
        mChkWallGndRoofTimer = cM::rndInt(10) + 20;
        if (mObjAcch2.ChkWallHit(nullptr) || mObjAcch2.ChkGndHit() || mObjAcch2.ChkRoofHit()) {
            mChkWallGndRoofTimer = 60;
            handleWallGndRoofHit();
            return true;
        }
    }
    return false;
}

void dAcBirdBase_c::handleWallGndRoofHit() {
    dBgS_ObjLinChk linChk;
    mVec3_c start, end;
    start.set(mPosition);
    end.set(mPosition);

    mVec3_c v1;
    mMtx_c m1;
    mMtx_c m2;

    mAng rot1 = field_0xF5C.atan2sX_Z();
    if (mObjAcch2.ChkGndHit()) {
        end.set(mPosition);
        v1.set(0.0f, 0.0f, 10000.0f);
        m1.YrotS(rot1);
        m1.XrotM(-0x4000);
        MTXMultVec(m1, v1, v1);
        end += v1;
        linChk.Set(&start, &end, nullptr);
        if (!dBgS::GetInstance()->LineCross(&linChk)) {
            field_0xF68.set(v1);
            field_0xF68.normalizeRS();
            return;
        }

        end.set(mPosition);
        v1.set(0.0f, 0.0f, 10000.0f);
        m1.YrotS(rot1);
        m1.XrotM(0x4000);
        MTXMultVec(m1, v1, v1);
        end += v1;
        linChk.Set(&start, &end, nullptr);
        if (!dBgS::GetInstance()->LineCross(&linChk)) {
            field_0xF68.set(v1);
            field_0xF68.normalizeRS();
            return;
        }
    }

    v1.set(0.0f, 0.0f, 10000.0f);
    v1.rotY(rot1 + mAng(0x4000));
    end += v1;
    linChk.Set(&start, &end, nullptr);
    if (!dBgS::GetInstance()->LineCross(&linChk)) {
        field_0xF68.set(v1);
        field_0xF68.normalizeRS();
        return;
    }

    end.set(mPosition);
    v1.set(0.0f, 0.0f, 10000.0f);
    v1.rotY(rot1 - mAng(0x4000));
    end += v1;
    linChk.Set(&start, &end, nullptr);
    if (!dBgS::GetInstance()->LineCross(&linChk)) {
        field_0xF68.set(v1);
        field_0xF68.normalizeRS();
        return;
    }

    end.set(mPosition);
    v1.set(0.0f, 0.0f, 10000.0f);
    m2.YrotS(rot1);
    m2.XrotM(0xC000);
    MTXMultVec(m2, v1, v1);
    end += v1;
    linChk.Set(&start, &end, nullptr);
    if (!dBgS::GetInstance()->LineCross(&linChk)) {
        field_0xF68.set(v1);
        field_0xF68.normalizeRS();
        return;
    }

    end.set(mPosition);
    v1.set(0.0f, 0.0f, 10000.0f);
    m2.YrotS(rot1);
    m2.XrotM(0x4000);
    MTXMultVec(m2, v1, v1);
    end += v1;
    linChk.Set(&start, &end, nullptr);
    if (!dBgS::GetInstance()->LineCross(&linChk)) {
        field_0xF68.set(v1);
        field_0xF68.normalizeRS();
        return;
    }
}
