#pragma once
#include <cstdint>

namespace Gen
{
    struct Serializer;
    struct Deserializer;
    struct PuzzleElementType
    {
        static constexpr uint16_t TypeIdx = 30;
        static constexpr int32_t EntryCount = 8;
        enum Enum : uint8_t
        {
            None,
            WaterIn,
            WaterGoal,
            WaterChannel,
            ElectricIn,
            ElectricGoal,
            Blocked,
            Bridge,
        };
        static constexpr char EntryNames[EntryCount][64]
        {
            "None",
            "WaterIn",
            "WaterGoal",
            "WaterChannel",
            "ElectricIn",
            "ElectricGoal",
            "Blocked",
            "Bridge",
        };
        static constexpr char GameName[EntryCount][64]
        {
            "Empty",
            "Water Source",
            "Water Goal",
            "Water Channel",
            "Electricity Source",
            "Electricity Goal",
            "Blocked",
            "Bridge",
        };
        static constexpr char ShortName[EntryCount][64]
        {
            "  ",
            "~+",
            "~!",
            "~",
            "e+",
            "e!",
            "B",
            "#",
        };
    };
    struct EMaterial
    {
        static constexpr uint16_t TypeIdx = 31;
        static constexpr int32_t EntryCount = 2;
        enum Enum : int32_t
        {
            Default,
            UI,
        };
        static constexpr char EntryNames[EntryCount][64]
        {
            "Default",
            "UI",
        };
    };
    struct Vec2
    {
        static constexpr uint16_t TypeIdx = 12;
        float x = {};
        float y = {};
    };
    struct Vec3
    {
        static constexpr uint16_t TypeIdx = 13;
        float x = {};
        float y = {};
        float z = {};
    };
    struct Vec4
    {
        static constexpr uint16_t TypeIdx = 14;
        float x = {};
        float y = {};
        float z = {};
        float w = {};
    };
    struct Mat3
    {
        static constexpr uint16_t TypeIdx = 15;
        float M[9] = {
	1.0f, 0.0f, 0.0f,
	0.0f, 1.0f, 0.0f,
	0.0f, 0.0f, 1.0f
	};
    };
    struct Mat4
    {
        static constexpr uint16_t TypeIdx = 16;
        float M[16] = {
	1.0f, 0.0f, 0.0f, 0.0f,
	0.0f, 1.0f, 0.0f, 0.0f,
	0.0f, 0.0f, 1.0f, 0.0f,
	0.0f, 0.0f, 0.0f, 1.0f
	};
    };
    struct Transform
    {
        static constexpr uint16_t TypeIdx = 17;
        Mat4 M = {};
        Mat4 MI = {};
        Vec3 Position = {};
        Mat4 Rotation = {};
        Vec3 Scale = {1.0f, 1.0f, 1.0f};
    };
    struct AssetHandle
    {
        static constexpr uint16_t TypeIdx = 18;
        uint32_t Idx = UINT32_MAX;
    };
    struct ModelHandle
    {
        static constexpr uint16_t TypeIdx = 19;
        uint16_t ModelIdx = UINT16_MAX;
        AssetHandle Asset = {};
    };
    struct TextureHandle
    {
        static constexpr uint16_t TypeIdx = 20;
        uint16_t TextureIdx = UINT16_MAX;
        AssetHandle Asset = {};
    };
    struct PuzPos
    {
        static constexpr uint16_t TypeIdx = 21;
        int8_t X = {};
        int8_t Y = {};
    };
    struct StaticPuzzleCard
    {
        static constexpr uint16_t TypeIdx = 22;
        PuzzleElementType::Enum Elements[4] = {};
        ModelHandle ModelHandle = {};
        TextureHandle ModelTextureHandle = {};
        TextureHandle BoardTextureHandle = {};
    };
    struct StaticPuzzleCardHandle
    {
        static constexpr uint16_t TypeIdx = 23;
        uint16_t Idx = UINT16_MAX;
    };
    struct PuzzleVisualSettings
    {
        static constexpr uint16_t TypeIdx = 24;
        Vec4 TileBaseColor = {};
        Vec4 TileDotColor = {};
        Vec3 Test = {};
        Vec4 DisabledCardTint = {};
    };
    struct StaticPuzzleData
    {
        static constexpr uint16_t TypeIdx = 25;
        StaticPuzzleCard Cards[64] = {};
        PuzzleVisualSettings Visuals = {};
    };
    struct PuzzleCardStack
    {
        static constexpr uint16_t TypeIdx = 26;
        StaticPuzzleCardHandle RefCard = {};
        uint8_t MaxAvailableCount = {};
        uint8_t UsedCount = {};
    };
    struct PlacedPuzzleCard
    {
        static constexpr uint16_t TypeIdx = 27;
        StaticPuzzleCardHandle RefCard = {};
        PuzPos Position = {};
        uint8_t Rotation = {};
        bool IsLocked = {};
    };
    struct PuzzleData
    {
        static constexpr uint16_t TypeIdx = 28;
        uint16_t ID = {};
        char PuzzleName[64] = {};
        uint8_t WidthTiles = {};
        uint8_t HeightTiles = {};
        uint32_t AvailableCardCount = {};
        PuzzleCardStack AvailableCards[16] = {};
        PlacedPuzzleCard PlacedCards[256] = {};
        PuzzleElementType::Enum BackgroundTiles[1024] = {};
        uint32_t GoalPositionCount = {};
        PuzPos GoalPositions[16] = {};
    };
    struct SavedEntityRenderData
    {
        static constexpr uint16_t TypeIdx = 29;
        Vec4 BaseColor = {};
        Vec4 HighlightColor = {};
        Transform TF = {};
        EMaterial::Enum Material = {};
        TextureHandle Texture = {};
        ModelHandle Model = {};
        bool Visible = {};
    };
    bool Save(const PuzzleElementType::Enum* obj, uint32_t count, Serializer& serializer);
    bool Load(PuzzleElementType::Enum* obj, uint32_t count, Deserializer& serializer);
    bool Save(const EMaterial::Enum* obj, uint32_t count, Serializer& serializer);
    bool Load(EMaterial::Enum* obj, uint32_t count, Deserializer& serializer);
    bool Save(const int8_t* obj, uint32_t count, Serializer& serializer);
    bool Load(int8_t* obj, uint32_t count, Deserializer& serializer);
    bool Save(const int16_t* obj, uint32_t count, Serializer& serializer);
    bool Load(int16_t* obj, uint32_t count, Deserializer& serializer);
    bool Save(const int32_t* obj, uint32_t count, Serializer& serializer);
    bool Load(int32_t* obj, uint32_t count, Deserializer& serializer);
    bool Save(const int64_t* obj, uint32_t count, Serializer& serializer);
    bool Load(int64_t* obj, uint32_t count, Deserializer& serializer);
    bool Save(const uint8_t* obj, uint32_t count, Serializer& serializer);
    bool Load(uint8_t* obj, uint32_t count, Deserializer& serializer);
    bool Save(const uint16_t* obj, uint32_t count, Serializer& serializer);
    bool Load(uint16_t* obj, uint32_t count, Deserializer& serializer);
    bool Save(const uint32_t* obj, uint32_t count, Serializer& serializer);
    bool Load(uint32_t* obj, uint32_t count, Deserializer& serializer);
    bool Save(const uint64_t* obj, uint32_t count, Serializer& serializer);
    bool Load(uint64_t* obj, uint32_t count, Deserializer& serializer);
    bool Save(const bool* obj, uint32_t count, Serializer& serializer);
    bool Load(bool* obj, uint32_t count, Deserializer& serializer);
    bool Save(const float* obj, uint32_t count, Serializer& serializer);
    bool Load(float* obj, uint32_t count, Deserializer& serializer);
    bool Save(const double* obj, uint32_t count, Serializer& serializer);
    bool Load(double* obj, uint32_t count, Deserializer& serializer);
    bool Save(const char* obj, uint32_t count, Serializer& serializer);
    bool Load(char* obj, uint32_t count, Deserializer& serializer);
    bool Save(const Vec2* obj, uint32_t count, Serializer& serializer);
    bool Load(Vec2* obj, uint32_t count, Deserializer& serializer);
    bool Save(const Vec3* obj, uint32_t count, Serializer& serializer);
    bool Load(Vec3* obj, uint32_t count, Deserializer& serializer);
    bool Save(const Vec4* obj, uint32_t count, Serializer& serializer);
    bool Load(Vec4* obj, uint32_t count, Deserializer& serializer);
    bool Save(const Mat3* obj, uint32_t count, Serializer& serializer);
    bool Load(Mat3* obj, uint32_t count, Deserializer& serializer);
    bool Save(const Mat4* obj, uint32_t count, Serializer& serializer);
    bool Load(Mat4* obj, uint32_t count, Deserializer& serializer);
    bool Save(const Transform* obj, uint32_t count, Serializer& serializer);
    bool Load(Transform* obj, uint32_t count, Deserializer& serializer);
    bool Save(const AssetHandle* obj, uint32_t count, Serializer& serializer);
    bool Load(AssetHandle* obj, uint32_t count, Deserializer& serializer);
    bool Save(const ModelHandle* obj, uint32_t count, Serializer& serializer);
    bool Load(ModelHandle* obj, uint32_t count, Deserializer& serializer);
    bool Save(const TextureHandle* obj, uint32_t count, Serializer& serializer);
    bool Load(TextureHandle* obj, uint32_t count, Deserializer& serializer);
    bool Save(const PuzPos* obj, uint32_t count, Serializer& serializer);
    bool Load(PuzPos* obj, uint32_t count, Deserializer& serializer);
    bool Save(const StaticPuzzleCard* obj, uint32_t count, Serializer& serializer);
    bool Load(StaticPuzzleCard* obj, uint32_t count, Deserializer& serializer);
    bool Save(const StaticPuzzleCardHandle* obj, uint32_t count, Serializer& serializer);
    bool Load(StaticPuzzleCardHandle* obj, uint32_t count, Deserializer& serializer);
    bool Save(const PuzzleVisualSettings* obj, uint32_t count, Serializer& serializer);
    bool Load(PuzzleVisualSettings* obj, uint32_t count, Deserializer& serializer);
    bool Save(const StaticPuzzleData* obj, uint32_t count, Serializer& serializer);
    bool Load(StaticPuzzleData* obj, uint32_t count, Deserializer& serializer);
    bool Save(const PuzzleCardStack* obj, uint32_t count, Serializer& serializer);
    bool Load(PuzzleCardStack* obj, uint32_t count, Deserializer& serializer);
    bool Save(const PlacedPuzzleCard* obj, uint32_t count, Serializer& serializer);
    bool Load(PlacedPuzzleCard* obj, uint32_t count, Deserializer& serializer);
    bool Save(const PuzzleData* obj, uint32_t count, Serializer& serializer);
    bool Load(PuzzleData* obj, uint32_t count, Deserializer& serializer);
    bool Save(const SavedEntityRenderData* obj, uint32_t count, Serializer& serializer);
    bool Load(SavedEntityRenderData* obj, uint32_t count, Deserializer& serializer);

    namespace Meta {
    struct StrRef
    {
        uint16_t Offset;
        uint16_t Size;
    };
    
    struct TypeDef
    {
        uint32_t Size = 0;
        uint32_t Hash = 0;
        char Name[64]{"Dummy"};
        uint16_t ChildCount = 0;
        uint16_t ChildIndices[64]{0};
        StrRef MemberNameIndices[64]{0};
    };

    struct MetadataTable
    {
        TypeDef TypeDefinitions[32]
        {
            TypeDef{sizeof(int8_t), 0, "i8", 0, {}, {}},
            TypeDef{sizeof(int16_t), 1, "i16", 0, {}, {}},
            TypeDef{sizeof(int32_t), 2, "i32", 0, {}, {}},
            TypeDef{sizeof(int64_t), 3, "i64", 0, {}, {}},
            TypeDef{sizeof(uint8_t), 4, "u8", 0, {}, {}},
            TypeDef{sizeof(uint16_t), 5, "u16", 0, {}, {}},
            TypeDef{sizeof(uint32_t), 6, "u32", 0, {}, {}},
            TypeDef{sizeof(uint64_t), 7, "u64", 0, {}, {}},
            TypeDef{sizeof(bool), 8, "b", 0, {}, {}},
            TypeDef{sizeof(float), 9, "f32", 0, {}, {}},
            TypeDef{sizeof(double), 10, "f64", 0, {}, {}},
            TypeDef{sizeof(char), 11, "str", 0, {}, {}},
            TypeDef{sizeof(Vec2), 2667033957, "Vec2", 2, {9, 9}, {{0, 1}, {1, 1}}},
            TypeDef{sizeof(Vec3), 473740858, "Vec3", 3, {9, 9, 9}, {{2, 1}, {3, 1}, {4, 1}}},
            TypeDef{sizeof(Vec4), 2507696603, "Vec4", 4, {9, 9, 9, 9}, {{5, 1}, {6, 1}, {7, 1}, {8, 1}}},
            TypeDef{sizeof(Mat3), 3364737048, "Mat3", 1, {9}, {{9, 1}}},
            TypeDef{sizeof(Mat4), 1650094019, "Mat4", 1, {9}, {{10, 1}}},
            TypeDef{sizeof(Transform), 4103530190, "Transform", 5, {16, 16, 13, 16, 13}, {{11, 1}, {12, 2}, {14, 8}, {22, 8}, {30, 5}}},
            TypeDef{sizeof(AssetHandle), 2609735487, "AssetHandle", 1, {6}, {{35, 3}}},
            TypeDef{sizeof(ModelHandle), 298089627, "ModelHandle", 2, {5, 18}, {{38, 8}, {46, 5}}},
            TypeDef{sizeof(TextureHandle), 1633273761, "TextureHandle", 2, {5, 18}, {{51, 10}, {61, 5}}},
            TypeDef{sizeof(PuzPos), 1834398141, "PuzPos", 2, {0, 0}, {{66, 1}, {67, 1}}},
            TypeDef{sizeof(StaticPuzzleCard), 1466565767, "StaticPuzzleCard", 4, {30, 19, 20, 20}, {{68, 8}, {76, 11}, {87, 18}, {105, 18}}},
            TypeDef{sizeof(StaticPuzzleCardHandle), 1742502768, "StaticPuzzleCardHandle", 1, {5}, {{123, 3}}},
            TypeDef{sizeof(PuzzleVisualSettings), 2302077481, "PuzzleVisualSettings", 4, {14, 14, 13, 14}, {{126, 13}, {139, 12}, {151, 4}, {155, 16}}},
            TypeDef{sizeof(StaticPuzzleData), 1131370538, "StaticPuzzleData", 2, {22, 24}, {{171, 5}, {176, 7}}},
            TypeDef{sizeof(PuzzleCardStack), 53538532, "PuzzleCardStack", 3, {23, 4, 4}, {{183, 7}, {190, 17}, {207, 9}}},
            TypeDef{sizeof(PlacedPuzzleCard), 3555575973, "PlacedPuzzleCard", 4, {23, 21, 4, 8}, {{216, 7}, {223, 8}, {231, 8}, {239, 8}}},
            TypeDef{sizeof(PuzzleData), 3349686056, "PuzzleData", 10, {5, 11, 4, 4, 6, 26, 27, 30, 6, 21}, {{247, 2}, {249, 10}, {259, 10}, {269, 11}, {280, 18}, {298, 14}, {312, 11}, {323, 15}, {338, 17}, {355, 13}}},
            TypeDef{sizeof(SavedEntityRenderData), 3172756855, "SavedEntityRenderData", 7, {14, 14, 17, 31, 20, 19, 8}, {{368, 9}, {377, 14}, {391, 2}, {393, 8}, {401, 7}, {408, 5}, {413, 7}}},
            TypeDef{sizeof(PuzzleElementType::Enum), 2983807453, "PuzzleElementType", 0, {}, {}},
            TypeDef{sizeof(EMaterial::Enum), 2024002654, "EMaterial", 0, {}, {}},
        };
        char MemberNameBuffer[64*64*64]{"xyxyzxyzwMMMMIPositionRotationScaleIdxModelIdxAssetTextureIdxAssetXYElementsModelHandleModelTextureHandleBoardTextureHandleIdxTileBaseColorTileDotColorTestDisabledCardTintCardsVisualsRefCardMaxAvailableCountUsedCountRefCardPositionRotationIsLockedIDPuzzleNameWidthTilesHeightTilesAvailableCardCountAvailableCardsPlacedCardsBackgroundTilesGoalPositionCountGoalPositionsBaseColorHighlightColorTFMaterialTextureModelVisible"};
    };

    constexpr MetadataTable Metadata;
    }
}
