#include "BlockType.h"
#include "ItemType.h"
#include "StaticRegistry.h"
// block types
#include "BasicBlocks.h"
#include "NoBlock.h"
#include "TreeSeblingBlock.h"
// dimensions
#include "OverworldDimension.h"
// entities
#include "ItemEntity.h"
#include "Player.h"
// item skills
#include "BasicItems.h"
#include "PlayerHand.h"
#include "StoneTool.h"
// world updates
#include "AddEntityUpdate.h"
#include "EntityRemovedUpdate.h"
// Multiblocks
#include "LightSources.h"
#include "MultiblockTree.h"

using namespace Framework;

void initializeBlockTypes()
{
    new NoBlockBlockType(BlockTypeEnum::NO_BLOCK, &NoBlock::INSTANCE);
    new NoBlockBlockType(BlockTypeEnum::AIR, &AirBlock::INSTANCE);

    (new BasicBlockType(BlockTypeEnum::DIRT,
         ItemTypeEnum::DIRT,
         ModelInfo("cube",
             {"blocks.ltdb/dirt.png",
                 "blocks.ltdb/dirt.png",
                 "blocks.ltdb/dirt.png",
                 "blocks.ltdb/dirt.png",
                 "blocks.ltdb/lawn.png",
                 "blocks.ltdb/dirt.png"}),
         "Dirt"))
        ->initializeDefault();
    (new BasicBlockType(BlockTypeEnum::STONE,
         ItemTypeEnum::STONE,
         ModelInfo("cube", "blocks.ltdb/stone.png", 6),
         "Stone"))
        ->setHardness(2.f)
        ->initializeDefault();
    (new BasicBlockType(BlockTypeEnum::SAND,
         ItemTypeEnum::SAND,
         ModelInfo("cube", "blocks.ltdb/sand.png", 6),
         "Sand"))
        ->setHardness(0.5f)
        ->initializeDefault();
    (new BasicBlockType(BlockTypeEnum::WOOD_OAK,
         ItemTypeEnum::WOOD_OAK,
         ModelInfo("cube", "blocks.ltdb/oak.png", 6),
         "Oak Wood"))
        ->setHardness(1.5f)
        ->initializeDefault();
    (new BasicBlockType(BlockTypeEnum::LEAVES_WOOD_OAK,
         ItemTypeEnum::LEAVES_WOOD_OAK,
         ModelInfo("cube", "blocks.ltdb/leaves.png", 6),
         [](Vec3<int> pos) {
             AdditionalItemSpawningBlock* block
                 = new AdditionalItemSpawningBlock(
                     BlockTypeEnum::LEAVES_WOOD_OAK, 0, pos);
             block->addSpawn({1, 1, 0.015, ItemTypeEnum::SEBLING_WOOD_OAK});
             return (Block*)block;
         },
         "Oak Wood Leaves"))
        ->setHardness(0.1f)
        ->initializeDefault();

    (new BasicBlockType(BlockTypeEnum::GRAVEL,
         ItemTypeEnum::GRAVEL,
         ModelInfo("cube", "blocks.ltdb/gravel.png", 6),
         "Gravel"))
        ->setHardness(0.75f)
        ->initializeDefault();
    (new BasicBlockType(BlockTypeEnum::STONE_GRANITE,
         ItemTypeEnum::STONE_GRANITE,
         ModelInfo("cube", "blocks.ltdb/granite.png", 6),
         "Granite Stone"))
        ->setHardness(3.f)
        ->initializeDefault();
    (new BasicBlockType(BlockTypeEnum::STONE_COBBLE,
         ItemTypeEnum::STONE_COBBLE,
         ModelInfo("cube", "blocks.ltdb/cobble.png", 6),
         "Cobble Stone"))
        ->setHardness(1.f)
        ->initializeDefault();
    (new BasicBlockType(BlockTypeEnum::WOOD_BIRCH,
         ItemTypeEnum::WOOD_BIRCH,
         ModelInfo("cube", "blocks.ltdb/birch.png", 6),
         "Birch Wood"))
        ->setHardness(1.5f)
        ->initializeDefault();
    (new BasicBlockType(BlockTypeEnum::LEAVES_WOOD_BIRCH,
         ItemTypeEnum::LEAVES_WOOD_BIRCH,
         ModelInfo("cube", "blocks.ltdb/leaves.png", 6),
         [](Vec3<int> pos) {
             AdditionalItemSpawningBlock* block
                 = new AdditionalItemSpawningBlock(
                     BlockTypeEnum::LEAVES_WOOD_BIRCH, 0, pos);
             block->addSpawn({1, 1, 0.03, ItemTypeEnum::SEBLING_WOOD_BIRCH});
             return (Block*)block;
         },
         "Birch Wood Leaves"))
        ->setHardness(0.1f)
        ->initializeDefault();

    (new BasicBlockType(BlockTypeEnum::WOOD_BEECH,
         ItemTypeEnum::WOOD_BEECH,
         ModelInfo("cube", "blocks.ltdb/beech.png", 6),
         "Beech Wood"))
        ->setHardness(1.5f)
        ->initializeDefault();
    (new BasicBlockType(BlockTypeEnum::LEAVES_WOOD_BEECH,
         ItemTypeEnum::LEAVES_WOOD_BEECH,
         ModelInfo("cube", "blocks.ltdb/leaves.png", 6),
         [](Vec3<int> pos) {
             AdditionalItemSpawningBlock* block
                 = new AdditionalItemSpawningBlock(
                     BlockTypeEnum::LEAVES_WOOD_BEECH, 0, pos);
             block->addSpawn({1, 1, 0.02, ItemTypeEnum::SEBLING_WOOD_BEECH});
             return (Block*)block;
         },
         "Beech Wood Leaves"))
        ->setHardness(0.1f)
        ->initializeDefault();

    (new BasicBlockType(BlockTypeEnum::STONE_BASALT,
         ItemTypeEnum::STONE_BASALT,
         ModelInfo("cube", "blocks.ltdb/basalt.png", 6),
         "Basalt Stone"))
        ->setHardness(2.f)
        ->initializeDefault();
    (new BasicBlockType(BlockTypeEnum::WOOD_PINE,
         ItemTypeEnum::WOOD_PINE,
         ModelInfo("cube", "blocks.ltdb/pine.png", 6),
         "Pine Wood"))
        ->setHardness(1.4f)
        ->initializeDefault();
    (new BasicBlockType(BlockTypeEnum::LEAVES_WOOD_PINE,
         ItemTypeEnum::LEAVES_WOOD_PINE,
         ModelInfo("cube", "blocks.ltdb/leaves.png", 6),
         [](Vec3<int> pos) {
             AdditionalItemSpawningBlock* block
                 = new AdditionalItemSpawningBlock(
                     BlockTypeEnum::LEAVES_WOOD_PINE, 0, pos);
             block->addSpawn({1, 1, 0.025, ItemTypeEnum::SEBLING_WOOD_PINE});
             return (Block*)block;
         },
         "Pine Wood Leaves"))
        ->setHardness(0.1f)
        ->initializeDefault();

    (new BasicLightSourceBlockType(BlockTypeEnum::TORCH,
         ItemTypeEnum::TORCH,
         ModelInfo("blocks.m3/torch", "blocks.ltdb/torch.png", 6),
         "Torch"))
        ->setHardness(0.f)
        ->setColor(0x00F69A54)
        ->initializeDefault();

    (new TreeSeblingBlockType(BlockTypeEnum::SEBLING_WOOD_OAK,
         ItemTypeEnum::SEBLING_WOOD_OAK,
         ModelInfo("blocks.m3/sebling", "blocks.ltdb/sebling.png", 1),
         BlockTypeEnum::WOOD_OAK,
         BlockTypeEnum::LEAVES_WOOD_OAK,
         "Oak Wood Sebling"))
        ->setHardness(0.1f)
        ->initializeDefault();
    (new TreeSeblingBlockType(BlockTypeEnum::SEBLING_WOOD_BIRCH,
         ItemTypeEnum::SEBLING_WOOD_BIRCH,
         ModelInfo("blocks.m3/sebling", "blocks.ltdb/sebling.png", 1),
         BlockTypeEnum::WOOD_BIRCH,
         BlockTypeEnum::LEAVES_WOOD_BIRCH,
         "Birch Wood Sebling"))
        ->setHardness(0.1f)
        ->initializeDefault();
    (new TreeSeblingBlockType(BlockTypeEnum::SEBLING_WOOD_BEECH,
         ItemTypeEnum::SEBLING_WOOD_BEECH,
         ModelInfo("blocks.m3/sebling", "blocks.ltdb/sebling.png", 1),
         BlockTypeEnum::WOOD_BEECH,
         BlockTypeEnum::LEAVES_WOOD_BEECH,
         "Beech Wood Sebling"))
        ->setHardness(0.1f)
        ->initializeDefault();
    (new TreeSeblingBlockType(BlockTypeEnum::SEBLING_WOOD_PINE,
         ItemTypeEnum::SEBLING_WOOD_PINE,
         ModelInfo("blocks.m3/sebling", "blocks.ltdb/sebling.png", 1),
         BlockTypeEnum::WOOD_PINE,
         BlockTypeEnum::LEAVES_WOOD_PINE, "Pine Wood Sebling"))
        ->setHardness(0.1f)
        ->initializeDefault();
}

void initializeItemTypes()
{
    (new BasicBlockItemType(ItemTypeEnum::DIRT,
        "Dirt",
        0,
        0,
        ModelInfo("itemCube", "blocks.ltdb/dirt.png", 6),
        BlockTypeEnum::DIRT));
    (new BasicBlockItemType(ItemTypeEnum::STONE,
         "Stone",
         0,
         0,
         ModelInfo("itemCube", "blocks.ltdb/stone.png", 6),
         BlockTypeEnum::STONE))
        ->setHardness(2.f);
    (new BasicBlockItemType(ItemTypeEnum::SAND,
         "Sand",
         0,
         0,
         ModelInfo("itemCube", "blocks.ltdb/sand.png", 6),
         BlockTypeEnum::SAND))
        ->setHardness(0.5f);
    (new BasicBlockItemType(ItemTypeEnum::WOOD_OAK,
         "Oak",
         0,
         0,
         ModelInfo("itemCube", "blocks.ltdb/oak.png", 6),
         BlockTypeEnum::WOOD_OAK))
        ->setHardness(1.5f);
    (new BasicBlockItemType(ItemTypeEnum::LEAVES_WOOD_OAK,
         "Oak Leaves",
         0,
         0,
         ModelInfo("itemCube", "blocks.ltdb/leaves.png", 6),
         BlockTypeEnum::LEAVES_WOOD_OAK))
        ->setHardness(0.1f);
    (new BasicBlockItemType(ItemTypeEnum::SEBLING_WOOD_OAK,
         "Oak Sebling",
         0,
         0,
         ModelInfo("blocks.m3/sebling", "blocks.ltdb/sebling.png", 1),
         BlockTypeEnum::SEBLING_WOOD_OAK))
        ->setHardness(0.1f);
    (new BasicBlockItemType(ItemTypeEnum::GRAVEL,
         "Gravel",
         0,
         0,
         ModelInfo("itemCube", "blocks.ltdb/gravel.png", 6),
         BlockTypeEnum::GRAVEL))
        ->setHardness(0.75f);
    (new BasicBlockItemType(ItemTypeEnum::STONE_GRANITE,
         "Granite",
         0,
         0,
         ModelInfo("itemCube", "blocks.ltdb/granite.png", 6),
         BlockTypeEnum::STONE_GRANITE))
        ->setHardness(3.f);
    (new BasicBlockItemType(ItemTypeEnum::STONE_COBBLE,
         "Cobble",
         0,
         0,
         ModelInfo("itemCube", "blocks.ltdb/cobble.png", 6),
         BlockTypeEnum::STONE_COBBLE))
        ->setHardness(1.f);
    (new BasicBlockItemType(ItemTypeEnum::WOOD_BIRCH,
         "Birch",
         0,
         0,
         ModelInfo("itemCube", "blocks.ltdb/birch.png", 6),
         BlockTypeEnum::WOOD_BIRCH))
        ->setHardness(1.5f);
    (new BasicBlockItemType(ItemTypeEnum::LEAVES_WOOD_BIRCH,
         "Birch Leaves",
         0,
         0,
         ModelInfo("itemCube", "blocks.ltdb/leaves.png", 6),
         BlockTypeEnum::LEAVES_WOOD_BIRCH))
        ->setHardness(0.1f);
    (new BasicBlockItemType(ItemTypeEnum::SEBLING_WOOD_BIRCH,
         "Birch Sebling",
         0,
         0,
         ModelInfo("blocks.m3/sebling", "blocks.ltdb/sebling.png", 1),
         BlockTypeEnum::SEBLING_WOOD_BIRCH))
        ->setHardness(0.1f);
    (new BasicBlockItemType(ItemTypeEnum::WOOD_BEECH,
         "Beech",
         0,
         0,
         ModelInfo("itemCube", "blocks.ltdb/beech.png", 6),
         BlockTypeEnum::WOOD_BEECH))
        ->setHardness(1.5f);
    (new BasicBlockItemType(ItemTypeEnum::LEAVES_WOOD_BEECH,
         "Beech Leaves",
         0,
         0,
         ModelInfo("itemCube", "blocks.ltdb/leaves.png", 6),
         BlockTypeEnum::LEAVES_WOOD_BEECH))
        ->setHardness(0.1f);
    (new BasicBlockItemType(ItemTypeEnum::SEBLING_WOOD_BEECH,
         "Beech Sebling",
         0,
         0,
         ModelInfo("blocks.m3/sebling", "blocks.ltdb/sebling.png", 1),
         BlockTypeEnum::SEBLING_WOOD_BEECH))
        ->setHardness(0.1f);
    (new BasicBlockItemType(ItemTypeEnum::STONE_BASALT,
         "Basalt",
         0,
         0,
         ModelInfo("itemCube", "blocks.ltdb/basalt.png", 6),
         BlockTypeEnum::STONE_BASALT))
        ->setHardness(2.f);
    (new BasicBlockItemType(ItemTypeEnum::WOOD_PINE,
         "Pine",
         0,
         0,
         ModelInfo("itemCube", "blocks.ltdb/pine.png", 6),
         BlockTypeEnum::WOOD_PINE))
        ->setHardness(1.4f);
    (new BasicBlockItemType(ItemTypeEnum::LEAVES_WOOD_PINE,
         "Pine Leaves",
         0,
         0,
         ModelInfo("itemCube", "blocks.ltdb/leaves.png", 6),
         BlockTypeEnum::LEAVES_WOOD_PINE))
        ->setHardness(0.1f);
    (new BasicBlockItemType(ItemTypeEnum::SEBLING_WOOD_PINE,
         "Pine Sebling",
         0,
         0,
         ModelInfo("blocks.m3/sebling", "blocks.ltdb/sebling.png", 1),
         BlockTypeEnum::SEBLING_WOOD_PINE))
        ->setHardness(0.1f);

    (new LightSourceItemType(ItemTypeEnum::TORCH,
         "Torch",
         ModelInfo("items.m3/stick", "blocks.ltdb/torch.png", 6),
         BlockTypeEnum::TORCH))
        ->setColor(0x00F69A54);

    new PlayerHandItemType();
    new StoneToolItemType();

    (new NoBlockItemType(ItemTypeEnum::WOOD_STICK,
        "WoodenStick",
        0,
        0,
        ModelInfo("items.m3/stick", "items.ltdb/stick.png", 1),
        []() {
            return ItemType::createBasicItem(ItemTypeEnum::WOOD_STICK,
                "Wooden Stick",
                1.f,
                1.f,
                10.f,
                10.f,
                0,
                0,
                0,
                1,
                0,
                50);
        }));
    (new NoBlockItemType(ItemTypeEnum::RESIN,
        "Resin",
        0,
        0,
        ModelInfo("itemCube", "items.ltdb/resin.png", 6),
        []() {
            return ItemType::createBasicItem(ItemTypeEnum::RESIN,
                "Resin",
                1.f,
                1.f,
                10.f,
                10.f,
                0,
                0,
                0,
                1,
                0,
                50);
        }));
    (new NoBlockItemType(ItemTypeEnum::STONE_TOOL_BROKEN,
        "BrokenStoneTool",
        0,
        0,
        ModelInfo("itemCube", "blocks.ltdb/stone.png", 6),
        []() {
            return ItemType::createBasicItem(ItemTypeEnum::STONE_TOOL_BROKEN,
                "Stone Tool",
                100.f,
                100.f,
                100.f,
                100.f,
                0,
                0,
                0,
                1,
                0,
                10);
        }));
}

void initializeEntityTypes()
{
    new PlayerEntityType();
    new ItemEntityType();
}

void initializeDimensions()
{
    new OverworldDimension();
}

void initializeMultiblockTypes()
{
    new MultiblockTreeStructureType();
}