#include "d/col/c/c_m3d.h"

#include "d/col/c/c_m3d_g_aab.h"
#include "d/col/c/c_m3d_g_cir.h"
#include "d/col/c/c_m3d_g_cps.h"
#include "d/col/c/c_m3d_g_cyl.h"
#include "d/col/c/c_m3d_g_lin.h"
#include "d/col/c/c_m3d_g_pla.h"
#include "d/col/c/c_m3d_g_sph.h"
#include "d/col/c/c_m3d_g_tri.h"
#include "d/col/c/c_m3d_g_unk.h"
#include "egg/math/eggMath.h"
#include "m/m_vec.h"
#include "nw4r/math/math_types.h"
#include "rvl/MTX.h" // IWYU pragma: export
#include "rvl/MTX/vec.h"

using namespace nw4r::math;
using namespace EGG;

const f32 G_CM3D_F_ABS_MIN = 32 * FLT_EPSILON;

inline void cM3d_Cross(const VEC3 *pVecA, const VEC3 *pVecB, const VEC3 *pVecC, VEC3 *pVecOut) {
    VEC3 tmp1;
    VEC3 tmp2;
    VEC3Sub(&tmp1, pVecB, pVecA);
    VEC3Sub(&tmp2, pVecC, pVecA);

    VEC3Cross(pVecOut, &tmp1, &tmp2);
}

bool cM3d_Len2dSqPntAndSegLine(f32, f32, f32, f32, f32, f32, f32 *, f32 *, f32 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_Len3dSqPntAndSegLine(const cM3dGLin *, const VEC3 *, VEC3 *, f32 *, f32 *) {
    // TODO - returns false to satisfy warning
    return false;
}
f32 cM3d_SignedLenPlaAndPos(const cM3dGPla *, const VEC3 *) {
    // TODO - returns 0.0f to satisfy warning
    return 0.0f;
}

void cM3d_CalcPla(const VEC3 *pVecA, const VEC3 *pVecB, const VEC3 *pVecC, VEC3 *pVecOut, f32 *pD) {
    cM3d_Cross(pVecA, pVecB, pVecC, pVecOut);
    f32 mag = VEC3Len(pVecOut);
    if (fabsf(mag) > 0.05f) {
        VEC3Scale(pVecOut, pVecOut, Math<f32>::inv(mag));
        f32 dot = VEC3Dot(pVecOut, pVecA);
        *pD = -dot;
    } else {
        pVecOut->y = 0.0f;
        *pD = 0.0f;
        pVecOut->z = 0.0f;
        pVecOut->x = 0.0f;
    }
}
int cM3d_Check_LinLin(const cM3dGLin *, const cM3dGLin *, f32 *, f32 *) {
    // TODO - returns false to satisfy warning
    return 0;
}
bool cM3d_Cross_LinPla(const cM3dGLin *, const cM3dGPla *, VEC3 *, bool, bool) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_Cross_MinMaxBoxLine(const VEC3 *, const VEC3 *, const VEC3 *, const VEC3 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_InclusionCheckPosIn3PosBox3d(const VEC3 *, const VEC3 *, const VEC3 *, const VEC3 *, f32) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_CrossX_Tri(const cM3dGTri *, const VEC3 *, f32) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_CrossX_Tri(const cM3dGTri *, const VEC3 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_CrossY_Tri(const cM3dGTri *, const VEC3 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_CrossY_Tri_Front(const VEC3 &, const VEC3 &, const VEC3 &, const VEC3 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_CrossY_Tri(const cM3dGTri *, const VEC3 *, f32 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_CrossY_Tri(const cM3dGTri *, const VEC3 *, f32) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_CrossY_Tri(const cM3dGTri *, const VEC3 *, const cM3d_Range *, f32 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_CrossZ_Tri(const cM3dGTri *, const VEC3 *, f32) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_CrossZ_Tri(const cM3dGTri *, const VEC3 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_CrossZ_Tri(const cM3dGTri *, const VEC3 *, f32 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_Cross_LinTri(const cM3dGLin *, const cM3dGTri *, VEC3 *, bool, bool) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_Cross_LinTri(
    const cM3dGLin *, const VEC3 *, const VEC3 *, const VEC3 *, const cM3dGPla *, VEC3 *, bool, bool
) {
    // TODO - returns false to satisfy warning
    return false;
}

bool cM3d_Cross_LinTri_Easy(const cM3dGTri *pTri, const VEC3 *pPos) {
    if ((cM3d_IsZero(pTri->mNormal.x) || cM3d_CrossX_Tri(pTri, pPos)) &&
        (cM3d_IsZero(pTri->mNormal.y) || cM3d_CrossY_Tri(pTri, pPos)) &&
        (cM3d_IsZero(pTri->mNormal.z) || cM3d_CrossZ_Tri(pTri, pPos))) {
        return true;
    }
    return false;
}

bool cM3d_Cross_SphPnt(const cM3dGSph *pSph, const VEC3 *pPos) {
    f32 r2 = pSph->GetR();
    return VEC3DistSq(pSph->GetC(), pPos) < r2 * r2;
}

bool cM3d_Cross_LinSph(const cM3dGLin *, const cM3dGSph *, VEC3 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_Cross_LinSph_CrossPos(const cM3dGSph &, const cM3dGLin &, VEC3 *, VEC3 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_Cross_CylSph(const cM3dGCyl &, const cM3dGSph &, f32 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_Cross_CylSph(const cM3dGCyl &, const cM3dGSph &, VEC3 *, f32 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_Cross_SphSph(const cM3dGSph &, const cM3dGSph &, f32 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_Cross_SphSph(const cM3dGSph &, const cM3dGSph &, f32 *, f32 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_Cross_SphSph(const cM3dGSph &, const cM3dGSph &, VEC3 *) {
    // TODO - returns false to satisfy warning
    return false;
}

void cM3d_CalcSphVsTriCrossPoint(const cM3dGSph &pSph, const cM3dGTri &pTri, VEC3 *pPnt) {
    VEC3 scale, add;
    VECAdd(pTri.mA, pTri.mB, add);
    VECScale(add, scale, 0.5f);
    const f32 mag = VEC3DistSq(&scale, &pSph.GetC());
    if (cM3d_IsZero(mag)) {
        *pPnt = pSph.GetC();
        return;
    }
    const f32 rad = pSph.GetR();
    f32 a = rad / mag;

    cM3d_InDivPos2(&pSph.GetC(), &scale, a, pPnt);
}
bool cM3d_Cross_SphTri(const cM3dGSph *, const cM3dGTri *, VEC3 *, f32 *, VEC3 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_Cross_CylCyl(const cM3dGCyl *, const cM3dGCyl *, f32 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_Cross_CylCyl(const cM3dGCyl *, const cM3dGCyl *, VEC3 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_Cross_CylTri(const cM3dGCyl *, const cM3dGTri *, VEC3 *) {
    // TODO - returns false to satisfy warning
    return false;
}
int cM3d_Cross_CylLin(const cM3dGCyl *, const cM3dGLin *, VEC3 *, VEC3 *) {
    // TODO - returns false to satisfy warning
    return false;
}
int cM3d_Cross_CylPntPnt(const cM3dGCyl *, const VEC3 *, const VEC3 *, VEC3 *, VEC3 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_Cross_CylPnt(const cM3dGCyl *, const VEC3 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_Cross_CpsSph_CrossPos(const cM3dGCps &, const cM3dGSph &, const VEC3 &, VEC3 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_Cross_CpsSph(const cM3dGCps &, const cM3dGSph &, VEC3 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_Cross_TriTri(const cM3dGTri &, const cM3dGTri &, VEC3 *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_Cross_CpsTri(const cM3dGCps &, const cM3dGTri &, VEC3 *) {
    // TODO - returns false to satisfy warning
    return false;
}
void cM3d_CalcVecZAngle(const VEC3 &, mAng3_c *) {}
void cM3d_PlaneCrossLineProcWork(f32, f32, f32, f32, f32, f32, f32, f32 *, f32 *) {}
int cM3d_2PlaneCrossLine(const cM3dGPla &, const cM3dGPla &, cM3dGLin *) {
    // TODO - returns false to satisfy warning
    return false;
}
bool cM3d_3PlaneCrossPos(const cM3dGPla &, const cM3dGPla &, const cM3dGPla &, VEC3 *) {
    // TODO - returns false to satisfy warning
    return false;
}
f32 cM3d_lineVsPosSuisenCross(const cM3dGLin &, const VEC3 &, VEC3 *) {
    // TODO - returns 0.0f to satisfy warning
    return 0.0f;
}
f32 cM3d_lineVsPosSuisenCross(const VEC3 &, const VEC3 &, const VEC3 &, VEC3 *) {
    // TODO - returns 0.0f to satisfy warning
    return 0.0f;
}

bool cM3d_Normalize(nw4r::math::VEC3 *pPnt) {
    f32 mag = VECMag(*pPnt);
    if (cM3d_IsZero(mag)) {
        return true;
    }
    mag = 1.f / mag;
    pPnt->x *= mag;
    pPnt->y *= mag;
    pPnt->z *= mag;
    return false;
}

void cM3d_Normalize_Ex(nw4r::math::VEC3 *pPnt) {
    if (cM3d_Normalize(pPnt)) {
        pPnt->x = 1.0f;
        pPnt->y = 0.0f;
        pPnt->z = 0.0f;
    }
}
