//
// Created by Tristan on 11/11/2025.
//

#ifndef WMO_STRUCTS_H
#define WMO_STRUCTS_H
#include "StormLib.h"
#include "glad/glad.h"

/* ---------- Enums ---------- */
typedef enum
{
    Flag_XAxis = 0x0,
    Flag_YAxis = 0x1,
    Flag_ZAxis = 0x2,
    Flag_AxisMask = 0x3,
    Flag_Leaf = 0x4,
    Flag_NoChild = 0xFFFF,
  } Flags;

/* ---------- Helper Structs ---------- */

typedef struct {
    uint16_t flags;        // See above enum (Flags). 4: leaf, 0 for YZ-plane, 1 for XZ-plane, 2 for XY-plane
    int16_t negChild;      // index of bsp child node (right in this array)
    int16_t posChild;
    uint16_t nFaces;       // num of triangle faces in MOBR
    uint32_t faceStart;    // index of the first triangle index(in MOBR)
    float planeDist;
} CAaBspNode;

// unions allow access to a single uint32 or component value
typedef union {
    uint32_t raw_value;
    struct {
        uint8_t a, r, g, b; // TODO: check endianness
    } components;
} CArgb;

// Axis-aligned bounding box
typedef struct {
    float min[3];
    float max[3];
} CAabox;

// TODO: keep C2/C3/C4 vector struct definitions or use the vec2_t/vec3_t/vec4_t structs
//  potentially could wrap them in a define and just have C2Vector/C3/C4 mean vec2/vec3/vec4 but thats not very ideal I imagine...
typedef struct {
    float x;
    float y;
} C2Vector;

typedef struct {
    float x;
    float y;
    float z;
} C3Vector;

typedef struct {
    C3Vector normal;
    float distance;
} C4Plane;

// MOHD
typedef struct {
    uint32_t nTextures;         // 0x00: number of textures (BLP files)
    uint32_t nGroups;           // 0x04: number of WMO groups
    uint32_t nPortals;          // 0x08: number of portals
    uint32_t nLights;           // 0x0C: number of lights
    uint32_t nModels;           // 0x10: number of M2 models imported
    uint32_t nDoodadDefs;       // 0x14: number of doodads (M2 instances)
    uint32_t nDoodadSets;       // 0x18: number of doodad sets
    CArgb amColor;              // 0x1C:
    uint32_t wmoID;             // 0x20: Foreign key for WMOAreaTableRec::m_WMOID (column 2 in WMOAreaTable.dbc)
    CAabox bounding_box;        // 0x24:
    uint32_t flags;             // 0x3C: Combined 16-bit flags field
    uint32_t numLOD;            // 0x3E:
} SMOHeader;

typedef struct {
    uint32_t flags;             // 0x00;
    CAabox bounding_box;        // 0x04;
    int32_t name_offset;        // 0x1C;
} SMOGroupInfo;

typedef struct {
    uint32_t flags;                 // 0x00: Material Flags
    uint32_t shader;                // 0x04: Shader Index
    uint32_t blendMode;             // 0x08: Blending (EGxBlend)
    uint32_t texture_name_offset;   // 0x0C: Offset into MOTX string block

    uint32_t sidnColor;             // 0x10: Emissive color (CImVector)
    uint32_t frameSidnColor;        // 0x14: SIDN emissive color (CImVector)
    uint32_t texture_2_offset;      // 0x18: Secondary texture offset/ID
    uint32_t diffColor;             // 0x1C: Diffuse color (CImVector)
    uint32_t ground_type;           // 0x20: TerrainTypeRec::m_ID

    uint32_t texture_3_offset;      // 0x24: Tertiary texture offset/ID
    uint32_t color_2;               // 0x28:
    uint32_t flags_2;               // 0x2C:
    uint32_t runTimeData[4];        // 0x30: 16 bytes of runtime data
} SMOMaterial;

// MOPT
typedef struct {
    uint16_t startVertex;
    uint16_t count;
    C4Plane plane;
} SMOPortal;

// MOPR
typedef struct {
    uint16_t portalIndex;       // into MOPT
    uint16_t groupIndex;        // the other one? (MOGI?)
    int16_t side;               // positive or negative
    uint16_t padding;           // filler
} SMOPortalRef;

typedef struct {
    int16_t x, y, z;
} SInt16Vector;

// MOBA
typedef struct {
    SInt16Vector min_bound;         // Part of the bounding box
    SInt16Vector max_bound;         // Part of the bounding box
    uint32_t startIndex;            // 0x0C: index of first face used in MOVI
    uint16_t count;                 // 0x10: number of MOVI indices used
    uint16_t minIndex;              // 0x12: index of the first vertex used in MOVT
    uint16_t maxIndex;              // 0x14: index of the last vertex used (batch includes this one)
    uint8_t flag_unk1;              // 0x16:
    uint8_t material_id;            // 0x17 index in MOMT
} SMOBatch;

typedef struct {
    uint8_t f_unk : 1;                          // 0x01: Bit 0
    uint8_t f_noCamCollide : 1;                 // 0x02: Bit 1
    uint8_t f_detail : 1;                       // 0x04: Bit 2
    uint8_t f_collision : 1;                    // 0x08: Bit 3 turn off water rippling effects
    uint8_t f_hint : 1;                         // 0x10: Bit 4
    uint8_t f_render : 1;                       // 0x20: Bit 5
    uint8_t f_cullObjects : 1;                  // 0x40: Bit 6
    uint8_t f_collideHit : 1;                   // 0x80: Bit 7
} SMOPolyFlags;

typedef struct {
    SMOPolyFlags flags;
    uint8_t material_id;
} SMOPoly;

typedef struct {
    uint32_t bspTree : 1;                       // 0x01: Bit 0 (MOBN and MOBR chunk)
    uint32_t lightMap : 1;                      // 0x02: Bit 1 (MOLM, MOLD)
    uint32_t vertexColors : 1;                  // 0x04: Bit 3 (MOCV)
    uint32_t renderExterior : 1;                // 0x08: Bit 4 (SMOGroup::EXTERIOR)
    uint32_t unused1 : 1;                       // 0x10: Bit 5
    uint32_t unused2 : 1;                       // 0x20: Bit 6
    uint32_t useExteriorLighting : 1;           // 0x40: Bit 7
    uint32_t unreachable : 1;                   // 0x80: Bit 8
    uint32_t useExteriorSky : 1;                // 0x100: Bit 9 (for interiors of city in stratholme_past.wmo)
    uint32_t hasLights : 1;                     // 0x200: Bit 10 (MOLR)
    uint32_t hasChunks : 1;                     // 0x400: Bit 11 (Has MPBV, MPBP, MPBI, MPBG chunks, doesnt actually use tho)
    uint32_t hasDoodads : 1;                    // 0x800: Bit 12
    uint32_t hasWater : 1;                      // 0x1000: Bit 13 (SMOGroup::LIQUIDSURFACE)
    uint32_t isIndoor : 1;                      // 0x2000: Bit 14 (SMOGroup::INTERIOR)
    uint32_t unsued3 : 1;                       // 0x4000: Bit 15
    uint32_t queryMountAllowed : 1;             // 0x8000: Bit 16 QueryMountAllowed in pre-WOTLK
    uint32_t alwaysDraw : 1;                    // 0x10000: Bit 17 SMOGroup::ALWAYSDRAW -- clear 0x8 after CMapObjGroup::Create() in MOGP and MOGI
    uint32_t unsued4 : 1;                       // 0x20000: Bit 18 Has MORI and MORB chunks
    uint32_t showSkybox : 1;                    // 0x40000: Bit 19 unset automatically if MOSB not present (TODO)
    uint32_t isNotWaterButOcean : 1;            // 0x80000: Bit 20 LiquidType related see (MLIQ chunk)
    uint32_t unk1 : 1;                          // 0x100000: Bit 21
    uint32_t isMountAllowed : 1;                    // 0x200000: Bit 22 IsMountAllowed
    uint32_t unused5 : 1;                       // 0x400000: Bit 23 Unused
    uint32_t hasSecondVertexColors : 1;         // 0x01000000: Bit 24 (CVERTS2)
    uint32_t hasSecondTexCoords : 1;            // 0x02000000: Bit 25 (TVERTS2)
    uint32_t isAntiPortal : 1;                  // 0x04000000: Bit 26 (ANTIPORTAL)
    uint32_t disableBatchRender : 1;            // 0x08000000: Bit 27 (unk)
    uint32_t unused6 : 1;                       // 0x10000000: Bit 28 (UNUSED: 20740)
    uint32_t isExteriorCull : 1;                // 0x20000000: Bit 29 (EXTERIOR_CULL)
    uint32_t hasThirdTexCoords : 1;             // 0x40000000: Bit 30 (TVERTS3)
    uint32_t unk3 : 1;                          // 0x80000000: Bit 31
} SMOGroupFlags;

typedef struct {
    uint32_t canCutTerrain : 1;             // 0x01: Bit 0
    uint32_t unk2 : 1;                      // 0x02: Bit 1
    uint32_t unk4 : 1;                      // 0x04: Bit 2
    uint32_t unk8 : 1;                      // 0x08: Bit 3
    uint32_t unk0x10 : 1;                   // 0x10: Bit 4
    uint32_t unk0x20 : 1;                   // 0x20: Bit 5
    uint32_t padding : 26;
} SMOGroupFlags2;

// TODO: setup flag parsing for flags, as well as for MOGI and WMORootData
// MOGP -- contains all other chunks, variables are a header only, actual chunk size way larger
#pragma pack(push, 1)
typedef struct {
    uint32_t groupName;                         // 0x00: offset into MOGN
    uint32_t descriptiveGroupName;              // 0x04: offset into MOGN
    SMOGroupFlags flags;                        // 0x08: https://wowdev.wiki/WMO#MOGP_chunk
    CAabox boundingBox;                         // 0x0C: same as above, see group flags (same as in corresponding MOGI entry)
    uint16_t portalStart;                       // 0x24: index into MOPR
    uint16_t portalCount;                       // 0x26: number of MOPR items used after portalStart
    uint16_t transBatchCount;                   // 0x28:
    uint16_t intBatchCount;                     // 0x2A:
    uint16_t extBatchCount;                     // 0x2C:
    uint16_t padding_or_data;                   // 0x2E: wiki isn't sure if is padding or data... TODO
    uint8_t fogIds[4];                          // 0x30: ids in MFOG
    uint32_t groupLiquid;                       // 0x34: see MLIQ chunk https://wowdev.wiki/WMO#MLIQ_chunk
    uint32_t wmoGroupID;                        // 0x38: Foreign key for WMOAreaTableRec::m_WMOGroupID (column 4 in WMOAreaTable.dbc) https://wowdev.wiki/DB/WMOAreaTable
    SMOGroupFlags2 flags2;                      // 0x3C:
    uint32_t unk;                               // 0x40: Unused 20740?
} SMOGroupHeader;

typedef struct {
    uint16_t indices;
} MOVIChunk;

typedef struct {
    SMOGroupHeader header;

    const char *group_file_buffer;
    DWORD group_file_size;
    const char *mogx_data_ptr;          //
    DWORD mogx_size;
    const char *mopy_data_ptr;          //
    DWORD mopy_size;
    const char *mpy2_data_ptr;          // dragonflight... 10.0.0.46181
    DWORD mpy2_size;
    const char *movi_data_ptr;          // Indices
    DWORD movi_size;
    const char *movt_data_ptr;          // Vertices
    DWORD movt_size;
    const char *monr_data_ptr;          // Vertex normals
    DWORD monr_size;
    const char *motv_data_ptr;          //
    DWORD motv_size;
    const char *moba_data_ptr;          // Batch list (drawing regions)
    DWORD moba_size;
    const char *moqg_data_ptr;          //
    DWORD moqg_size;
    const char *molr_data_ptr;
    DWORD molr_size;
    // TODO: chunks dependent on flag, need to add their ptr's
} WMOGroupData;


/* ---------- Root WMO Data Struct ---------- */
typedef struct {
    // Material and Texture Data
    const char *mver_data_ptr;
    DWORD mver_size;
    const char *mohd_data_ptr;
    DWORD mohd_size;
    const char *motx_data_ptr;
    DWORD motx_size;
    const char *momt_data_ptr;
    DWORD momt_size;
    const char *mogn_data_ptr;
    DWORD mogn_size;
    const char *mogi_data_ptr;
    DWORD mogi_size;
    const char *mosb_data_ptr;
    DWORD mosb_size;
    const char *mopv_data_ptr;
    DWORD mopv_size;
    const char *mopt_data_ptr;
    DWORD mopt_size;
    const char *mopr_data_ptr;
    DWORD mopr_size;
    // for MOPR
    // SMOPortalRef *portal_references;
    // size_t portal_ref_count;
    const char *movv_data_ptr;
    DWORD movv_size;
    const char *movb_data_ptr;
    DWORD movb_size;
    const char *molt_data_ptr;
    DWORD molt_size;
    const char *mods_data_ptr;
    DWORD mods_size;
    const char *modn_data_ptr;
    DWORD modn_size;
    const char *modd_data_ptr;
    DWORD modd_size;
    const char *mfog_data_ptr;
    DWORD mfog_size;
    GLuint *material_textures; // Array of OpeNGL texture ids corresponding to MOMT entries
    WMOGroupData *groups;
    size_t group_count;
} WMORootData;

extern WMORootData out_wmo_data;


#endif //WMO_STRUCTS_H
