#pragma once

#if defined( __EMSCRIPTEN__ ) || defined( __ANDROID__ )
#include <GLES3/gl3.h>
#else
#include <glad/glad.h>
#endif

#include <SDL3/SDL.h>
#include <box3d/math_functions.h>
#include <box3d/types.h>

typedef enum CR_LogCategory
{
    CR_LOG_CATEGORY_TODO    = SDL_LOG_CATEGORY_CUSTOM,
    CR_LOG_CATEGORY_NET,
    CR_LOG_CATEGORY_PHYSICS,
    CR_LOG_CATEGORY_ECS,
    CR_LOG_CATEGORY_SAVELOAD,
    CR_LOG_CATEGORY_POSTPROCESS,
    CR_LOG_CATEGORY_ASSET_TEXTURE,
    CR_LOG_CATEGORY_ASSET_FONT,
    CR_LOG_CATEGORY_ASSET_AUDIO,
} CR_LogCategory;

struct int2
{
    int32_t x;
    int32_t y;
};

struct float2
{
    float x;
    float y;

    constexpr float2()
        : x( 0.0f )
        , y( 0.0f )
    {}

    constexpr float2( float x, float y )
        : x( x )
        , y( y )
    {}

    constexpr float2( b3Vec2 xy )
        : x( xy.x )
        , y( xy.y )
    {}

    constexpr float lengthsq() const
    {
        return ( x * x ) + ( y * y );
    }
    constexpr b3Vec2 b3()
    {
        return { x, y };
    }
};

struct float3
{
    float x;
    float y;
    float z;

    constexpr float3()
        : x( 0.0f )
        , y( 0.0f )
        , z( 0.0f )
    {}

    constexpr float3( float x, float y, float z )
        : x( x )
        , y( y )
        , z( z )
    {}

    constexpr float3( b3Vec3 xyz )
        : x( xyz.x )
        , y( xyz.y )
        , z( xyz.z )
    {}

    constexpr b3Vec3 b3()
    {
        return { x, y, z };
    }
};

struct quat4
{
    float x;
    float y;
    float z;
    float w;

    constexpr quat4()   // identity rotation
        : x( 0.0f )
        , y( 0.0f )
        , z( 0.0f )
        , w( 1.0f )
    {}

    constexpr quat4( float x, float y, float z, float w )
        : x( x )
        , y( y )
        , z( z )
        , w( w )
    {}

    constexpr quat4( b3Quat q )
        : x( q.v.x )
        , y( q.v.y )
        , z( q.v.z )
        , w( q.s )
    {}

    constexpr b3Quat b3()
    {
        return { { x, y, z }, w };
    }
};

struct float4x4
{
    float m[ 16 ];   // column-major (GL upload order)

    constexpr float4x4()
        : m{ 0, }
    {}

    constexpr float4x4( b3Matrix3 m3 )   // rotation promoted to 4x4 — translation zero
        : m{ m3.cx.x, m3.cx.y, m3.cx.z, 0.0f,
             m3.cy.x, m3.cy.y, m3.cy.z, 0.0f,
             m3.cz.x, m3.cz.y, m3.cz.z, 0.0f,
             0.0f,    0.0f,    0.0f,    1.0f }
    {}

    // NOT constexpr — delegates to box3d's b3MakeMatrixFromQuat, a plain (non-constexpr) library call
    float4x4( b3Quat q )
        : float4x4( b3MakeMatrixFromQuat( q ) )
    {}

    static constexpr float4x4 Identity()
    {
        float4x4 r;
        r.m[ 0 ]  = 1.0f;
        r.m[ 5 ]  = 1.0f;
        r.m[ 10 ] = 1.0f;
        r.m[ 15 ] = 1.0f;
        return r;
    }
};

// culling half-space — a point p is inside when Dot3( n, p ) + d >= 0 (n is unit)
struct crPlane
{
    float3 n;
    float  d;
};

// 6-plane view/light volume for sphere culling — built by crMath::FrustumFromMatrix
struct crFrustum
{
    crPlane planes[ 6 ];
};

// orthonormal direction frame (unit vectors)
struct crBasis
{
    float3 forward;
    float3 right;
    float3 up;
};

struct color4
{
    float r;
    float g;
    float b;
    float a;

    constexpr color4()
        : r( 0.0f )
        , g( 0.0f )
        , b( 0.0f )
        , a( 0.0f )
    {}

    constexpr color4( float r, float g, float b, float a )
        : r( r )
        , g( g )
        , b( b )
        , a( a )
    {}

    constexpr color4( b3HexColor b3Hex )
        : r( ( float )( ( ( int )b3Hex >> 16 ) & 0xff ) / 255.0f )
        , g( ( float )( ( ( int )b3Hex >>  8 ) & 0xff ) / 255.0f )
        , b( ( float )( ( ( int )b3Hex       ) & 0xff ) / 255.0f )
        , a( 1.0f )
    {}
};

struct crFrameDelta
{
    float unscaled = 0.0f;
    float scaled   = 0.0f;
};

// GL texture reference — produced by crTextureLoader::Load
struct crTexture
{
    GLuint handle = 0;   // 0 = load failed
    int2   size   = {};
};
