#pragma once

#include <glad/glad.h>
#include <glm/glm.hpp>
#include <optional>
#include <string>
#include <vector>

namespace Cubed {

using BlockType = uint8_t;
using OptionalBlockVectorArray =
    std::array<std::optional<std::vector<BlockType>>, 4>;

struct BlockTexture {
    std::string name;
    unsigned id;
    std::vector<GLuint> texture;
};

struct Block : public BlockTexture {};

struct BlockRenderData {
    std::vector<bool> draw_face;
    unsigned block_id;
    BlockRenderData() = default;
    BlockRenderData(const BlockRenderData&) = default;
    BlockRenderData& operator=(const BlockRenderData&) = default;
    BlockRenderData(BlockRenderData&& data)
        : draw_face(std::move(data.draw_face)), block_id(data.block_id) {}
    BlockRenderData& operator=(BlockRenderData&& data) {
        draw_face = std::move(data.draw_face);
        block_id = data.block_id;
        return *this;
    }
};

struct LookBlock {
    glm::ivec3 pos;
    glm::ivec3 normal;
};

struct BlockData {
    std::string name;
    BlockType id = 0;

    bool is_liquid = false;
    bool is_gas = false;

    bool is_passable = false;
    bool is_cross_plane = false;
    bool is_transparent = false;

    bool is_discard = false;
    bool is_blend = false;
    bool is_transitional = false;
    float roughness = 1.0f;
    BlockData(BlockType b_id, std::string_view b_name, bool liquid,
              bool passable, bool cross_plane, bool transparent, bool gas,
              bool discard, bool blend, bool transitional, float r)
        : name(b_name), id(b_id), is_liquid(liquid), is_gas(gas),
          is_passable(passable), is_cross_plane(cross_plane),
          is_transparent(transparent), is_discard(discard), is_blend(blend),
          is_transitional(transitional), roughness(r) {}
};

class BlockManager {

public:
    static const std::vector<BlockData>& datas();
    static void init();
    static unsigned sums();
    static unsigned cross_plane_sum();
    static const std::string& name_form_id(BlockType id);

    static bool is_gas(BlockType id);
    static bool is_liquid(BlockType id);

    static bool is_cross_plane(BlockType id);
    static bool is_transparent(BlockType id);
    static bool is_passable(BlockType id);

    static bool is_discard(BlockType id);
    static bool is_blend(BlockType id);
    static bool is_transitional(BlockType id);
    static float roughness(BlockType id);
    static BlockType cross_plane_index(BlockType id);

private:
    static void set_up_cross_plane_map();
    static inline std::vector<BlockData> m_datas;
    static inline bool is_init = false;
    static inline std::unordered_map<BlockType, BlockType> m_cross_plane_map;
};

} // namespace Cubed