#pragma once
#include <cstdint>

namespace Gen
{
    struct Serializer;
    struct Deserializer;
    struct KnownType
    {
        static constexpr uint16_t EnumIdx = 0;
        static constexpr int32_t EntryCount = 12;
        enum Enum : uint8_t
        {
            i8,
            i16,
            i32,
            i64,
            u8,
            u16,
            u32,
            u64,
            b,
            f32,
            f64,
            str,
        };
        static constexpr char EntryNames[EntryCount][64]
        {
            "i8",
            "i16",
            "i32",
            "i64",
            "u8",
            "u16",
            "u32",
            "u64",
            "b",
            "f32",
            "f64",
            "str",
        };
        static constexpr char CName[EntryCount][64]
        {
            "int8_t",
            "int16_t",
            "int32_t",
            "int64_t",
            "uint8_t",
            "uint16_t",
            "uint32_t",
            "uint64_t",
            "bool",
            "float",
            "double",
            "char",
        };
    };
    struct Test
    {
        static constexpr uint16_t TypeIdx = 12;
        uint32_t Number = {};
    };
    struct Texture
    {
        static constexpr uint16_t TypeIdx = 13;
        uint32_t Width = {};
        uint32_t Height = {};
        char StrTest[3] = {};
        Test T = {};
    };
    bool Save(const KnownType::Enum* obj, uint32_t count, Serializer& serializer);
    bool Load(KnownType::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 Test* obj, uint32_t count, Serializer& serializer);
    bool Load(Test* obj, uint32_t count, Deserializer& serializer);
    bool Save(const Texture* obj, uint32_t count, Serializer& serializer);
    bool Load(Texture* obj, uint32_t count, Deserializer& serializer);

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

    struct EnumDef
    {
        uint32_t Size = 0;
        uint32_t Hash = 0;
    };

    struct MetadataTable
    {
        TypeDef TypeDefinitions[14]
        {
            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(Test), 273256278, "Test", 1, {6}},
            TypeDef{sizeof(Texture), 992460010, "Texture", 4, {6, 6, 11, 12}},
        };
        EnumDef EnumDefinitions[1]
        {
            EnumDef{sizeof(KnownType::Enum), 2983807453},
        };
    };

    constexpr MetadataTable Metadata;
    }
}
