#include <Item/StatefulItem/Bag/Backpack/Backpack.hpp>
#include <Item/StatefulItem/Jetpack/Jetpack.hpp>
#include <Item/StatefulItem/PlutoniumCaptureCell/PlutoniumCaptureCell.hpp>
#include <Item/StatefulItem/Shoes/Shoes.hpp>
#include <ItemRegistry/ItemRegistry.hpp>
#include <Item/StatefulItem/BlockItem/BlockItem.hpp>
#include <Item/StatelessItem/BasicItem/BasicItem.hpp>
#include <Item/StatefulItem/BasicTool/Chisel/Chisel.hpp>
#include <Item/StatefulItem/BasicTool/Axe/Axe.hpp>
#include <Item/StatefulItem/BasicTool/Pickaxe/Pickaxe.hpp>
#include <Item/StatefulItem/Capsule/Capsule.hpp>
#include <Item/StatefulItem/Battery/Battery.hpp>
#include <Item/StatefulItem/ElectricDrill/ElectricDrill.hpp>
#include <Item/StatefulItem/FissionCell/FissionCell.hpp>
#include <Item/StatefulItem/MemoryChip/MemoryChip.hpp>
#include <Item/StatelessItem/BasicItem/Coil/Coil.hpp>
#include <Item/StatelessItem/BasicItem/MachineUpgrade/MachineUpgrade.hpp>
#include <Item/StatelessItem/BasicItem/Rake/Rake.hpp>
#include <Item/StatelessItem/BasicItem/Dye/Dye.hpp>
#include <Item/StatelessItem/BasicItem/BlackHoleBattery/BlackHoleBattery.hpp>
#include <Item/StatelessItem/BasicItem/CheatBattery/CheatBattery.hpp>
#include <Item/StatelessItem/BasicItem/CheatCapsule/CheatCapsule.hpp>
#include <Item/StatelessItem/BasicItem/CheatCoolant/CheatCoolant.hpp>
#include <Item/StatelessItem/BasicItem/CheatFertilizer/CheatFertilizer.hpp>
#include <Item/StatelessItem/BasicItem/HeatSink/HeatSink.hpp>
#include <Item/StatelessItem/BasicItem/Fan/Fan.hpp>
#include <Item/StatelessItem/BasicItem/NavItem/NavItem.hpp>
#include <Chunk/Chunk.hpp>
#include <BlockRegistry/BlockRegistry.hpp>

ItemRegistry itemRegistry;

ItemRegistry::~ItemRegistry()
{
    for (auto& [name, item] : items)
    {
        delete item;
    }
}

void ItemRegistry::registerAllItems()
{
    registerItem<BlockItem>("main:block");
    registerItem<BasicItem>("main:stick", "Stick", Material::stick);
    registerItem<BasicItem>("main:brick", "Brick", Material::brick);
    registerItem<BasicItem>("main:ironIngot", "Iron Ingot", Material::ironIngot);
    registerItem<BasicItem>("main:copperIngot", "Copper Ingot", Material::copperIngot);
    registerItem<BasicItem>("main:leadIngot", "Lead Ingot", Material::leadIngot);
    registerItem<BasicItem>("main:tinIngot", "Tin Ingot", Material::tinIngot);
    registerItem<BasicItem>("main:silverIngot", "Silver Ingot", Material::silverIngot);
    registerItem<BasicItem>("main:nickelIngot", "Nickel Ingot", Material::nickelIngot);
    registerItem<BasicItem>("main:goldIngot", "Gold Ingot", Material::goldIngot);
    registerItem<BasicItem>("main:steelIngot", "Steel Ingot", Material::steelIngot);
    registerItem<BasicItem>("main:tinCopperBundle", "Tin-copper Bundle", Material::tinCopperBundle);
    registerItem<BasicItem>("main:brassCopperBundle", "Brass-copper Bundle", Material::brassCopperBundle);
    registerItem<BasicItem>("main:brassIngot", "Brass Ingot", Material::brassIngot);
    registerItem<BasicItem>("main:bronzeIngot", "Bronze Ingot", Material::bronzeIngot);
    registerItem<BasicItem>("main:siliconIngot", "Silicon Ingot", Material::siliconIngot);
    registerItem<BasicItem>("main:ironDust", "Iron Dust", Material::ironDust);
    registerItem<BasicItem>("main:copperDust", "Copper Dust", Material::copperDust);
    registerItem<BasicItem>("main:leadDust", "Lead Dust", Material::leadDust);
    registerItem<BasicItem>("main:tinDust", "Tin Dust", Material::tinDust);
    registerItem<BasicItem>("main:silverDust", "Silver Dust", Material::silverDust);
    registerItem<BasicItem>("main:nickelDust", "Nickel Dust", Material::nickelDust);
    registerItem<BasicItem>("main:goldDust", "Gold Dust", Material::goldDust);
    registerItem<BasicItem>("main:steelDust", "Steel Dust", Material::steelDust);
    registerItem<BasicItem>("main:brassDust", "Brass Dust", Material::brassDust);
    registerItem<BasicItem>("main:bronzeDust", "Bronze Dust", Material::bronzeDust);
    registerItem<BasicItem>("main:uraniumDust", "Uranium Dust", Material::uraniumDust);
    registerItem<BasicItem>("main:siliconDust", "Silicon Dust", Material::siliconDust);
    registerItem<Dye>("main:blueDye", "blue", "Blue Dye", Material::blueDye);
    registerItem<Dye>("main:redDye", "red", "Red Dye", Material::redDye);
    registerItem<Dye>("main:greenDye", "green", "Green Dye", Material::greenDye);
    registerItem<Dye>("main:limeDye", "lime", "Lime Dye", Material::limeDye);
    registerItem<Dye>("main:darkGreenDye", "darkGreen", "Dark Green Dye", Material::darkGreenDye);
    registerItem<Dye>("main:yellowGreenDye", "yellowGreen", "Yellow Green Dye", Material::yellowGreenDye);
    registerItem<Dye>("main:yellowDye", "yellow", "Yellow Dye", Material::yellowDye);
    registerItem<Dye>("main:brownDye", "brown", "Brown Dye", Material::brownDye);
    registerItem<Dye>("main:blackDye", "black", "Black Dye", Material::blackDye);
    registerItem<Dye>("main:magentaDye", "magenta", "Magenta Dye", Material::magentaDye);
    registerItem<Dye>("main:cyanDye", "cyan", "Cyan Dye", Material::cyanDye);
    registerItem<Dye>("main:lightRedDye", "lightRed", "Light Red Dye", Material::lightRedDye);
    registerItem<Dye>("main:lightYellowDye", "lightYellow", "Light Yellow Dye", Material::lightYellowDye);
    registerItem<Dye>("main:coralDye", "coral", "Coral Dye", Material::coralDye);
    registerItem<Dye>("main:orangeDye", "orange", "Orange Dye", Material::orangeDye);
    registerItem<Dye>("main:darkYellowDye", "darkYellow", "Dark Yellow Dye", Material::darkYellowDye);
    registerItem<Dye>("main:tealDye", "teal", "Teal Dye", Material::tealDye);
    registerItem<Dye>("main:darkBlueDye", "darkBlue", "Dark Blue Dye", Material::darkBlueDye);
    registerItem<Dye>("main:pinkDye", "pink", "Pink Dye", Material::pinkDye);
    registerItem<Dye>("main:darkPinkDye", "darkPink", "Dark Pink Dye", Material::darkPinkDye);
    registerItem<Dye>("main:redOrangeDye", "redOrange", "Red-Orange Dye", Material::redOrangeDye);
    registerItem<Dye>("main:darkRedDye", "darkRed", "Dark Red Dye", Material::darkRedDye);
    registerItem<Dye>("main:darkBrownDye", "darkBrown", "Dark Brown Dye", Material::darkBrownDye);
    registerItem<Dye>("main:violetDye", "violet", "Violet Dye", Material::violetDye);
    registerItem<Dye>("main:purpleDye", "purple", "Purple Dye", Material::purpleDye);
    registerItem<Dye>("main:whiteDye", "white", "White Dye", Material::whiteDye);
    registerItem<BasicItem>("main:wheat", "Wheat", Material::wheat);
    registerItem<BasicItem>("main:rubberTreeSap", "Rubber Tree Sap", Material::rubberTreeSap);
    registerItem<BasicItem>("main:rubber", "Rubber", Material::rubber);
    registerItem<BasicItem>("main:quartz", "Quartz", Material::quartz);
    registerItem<BasicItem>("main:steelClaws", "Steel Claws", Material::steelClaws);
    registerItem<BasicItem>("main:emerald", "Emerald", Material::emerald);
    registerItem<BasicItem>("main:laser", "Laser", Material::laser);
    registerItem<Chisel>("main:chisel");
    registerItem<Axe>("main:basicAxe", Material::basicAxe, 8, 1.0f, "Basic Axe");
    registerItem<Axe>("main:stoneAxe", Material::stoneAxe, 32, 2.0f, "Stone Axe");
    registerItem<Axe>("main:bronzeAxe", Material::bronzeAxe, 64, 4.0f, "Bronze Axe");
    registerItem<Axe>("main:ironAxe", Material::ironAxe, 128, 8.0f, "Iron Axe");
    registerItem<Axe>("main:steelAxe", Material::steelAxe, 512, 16.0f, "Steel Axe");
    registerItem<Axe>("main:diamondAxe", Material::diamondAxe, 2048, 32.0f, "Diamond Axe");
    registerItem<Pickaxe>("main:stonePickaxe", Material::stonePickaxe, 128, 2.0f, "Stone Pickaxe", true);
    registerItem<Pickaxe>("main:bronzePickaxe", Material::bronzePickaxe, 256, 4.0f, "Bronze Pickaxe");
    registerItem<Pickaxe>("main:ironPickaxe", Material::ironPickaxe, 512, 8.0f, "Iron Pickaxe");
    registerItem<Pickaxe>("main:steelPickaxe", Material::steelPickaxe, 1024, 16.0f, "Steel Pickaxe");
    registerItem<Pickaxe>("main:diamondPickaxe", Material::diamondPickaxe, 4096, 32.0f, "Diamond Pickaxe");
    registerItem<Capsule>("main:capsuleSmallTin", CapsuleSize::Small, CapsuleTier::Tin, Material::capsuleSmallTin);
    registerItem<Capsule>("main:capsuleLargeTin", CapsuleSize::Large, CapsuleTier::Tin, Material::capsuleLargeTin);
    registerItem<Capsule>("main:capsuleSmallLead", CapsuleSize::Small, CapsuleTier::Lead, Material::capsuleSmallLead);
    registerItem<Capsule>("main:capsuleLargeLead", CapsuleSize::Large, CapsuleTier::Lead, Material::capsuleLargeLead);
    registerItem<BasicItem>("main:charcoal", "Charcoal", Material::charcoal);
    registerItem<BasicItem>("main:coal", "Coal", Material::coal);
    registerItem<BasicItem>("main:screwdriver", "Screwdriver", Material::screwdriver).setMaxStackSize(1);
    registerItem<Battery>("main:battery");
    registerItem<Coil>("main:coil");
    registerItem<BasicItem>("main:diamond", "Diamond", Material::diamond);
    registerItem<MachineUpgrade>("main:speedUpgrade", "Speed upgrade", Material::speedUpgrade, 4, 0);
    registerItem<MachineUpgrade>("main:efficiencyUpgrade", "Efficiency upgrade", Material::efficiencyUpgrade, 0, 1);
    registerItem<ElectricDrill>("main:electricDrill");
    registerItem<Rake>("main:rake");
    registerItem<BlackHoleBattery>("main:blackHoleBattery");
    registerItem<CheatBattery>("main:cheatBattery");
    registerItem<CheatCapsule>("main:waterCheatCapsule", "main:water", Material::waterCheatCapsule);
    registerItem<CheatCapsule>("main:petrolCheatCapsule", "main:petrol", Material::petrolCheatCapsule);
    registerItem<CheatCapsule>("main:oilCheatCapsule", "main:oil", Material::oilCheatCapsule);
    registerItem<CheatCapsule>("main:refuCheatCapsule", "main:refu", Material::refuCheatCapsule);
    registerItem<CheatCapsule>("main:plutoniumCheatCapsule", "main:plutonium", Material::plutoniumCheatCapsule);
    registerItem<CheatCoolant>("main:cheatCoolant");
    registerItem<HeatSink>("main:heatSink");
    registerItem<FissionCell>(
        "main:uraniumFissionCell",
        "Uranium Fission Cell",
        Material::uraniumFissionCell,
        "main:refu",
        700,
        360
    );
    registerItem<FissionCell>(
        "main:plutoniumFissionCell",
        "Plutonium Fission Cell",
        Material::plutoniumFissionCell,
        "main:plutonium",
        3500,
        180
    );
    registerItem<BasicItem>("main:turbine", "Turbine", Material::turbine);
    registerItem<BasicItem>("main:alternator", "Alternator", Material::alternator);
    registerItem<Fan>("main:fan1", "Fan Lv. 1", Material::fan1, 0.1f);
    registerItem<BasicItem>("main:siliconSheet", "Silicon Sheet", Material::siliconSheet);
    registerItem<CheatFertilizer>("main:cheatFertilizer");
    registerItem<BasicItem>("main:quartzFork", "Quartz Fork", Material::quartzFork);
    registerItem<BasicItem>("main:paperSheet", "Paper Sheet", Material::paperSheet);
    registerItem<BasicItem>("main:compass", "Compass", Material::compass);
    registerItem<NavItem>("main:carvedMap", "Carved Map", Material::carvedMap, NavItem::MapLevel::CarvedMap);
    registerItem<NavItem>("main:paperMap", "Paper Map", Material::paperMap, NavItem::MapLevel::PaperMap);
    registerItem<NavItem>("main:cheatMap", "Cheat Map", Material::cheatMap, NavItem::MapLevel::Cheat);
    registerItem<Jetpack>("main:jetpack");
    registerItem<BasicItem>("main:woodPulp", "Wood Pulp", Material::woodPulp);
    registerItem<BasicItem>("main:mushroomLeather", "Mushroom Leather", Material::mushroomLeather);
    registerItem<Shoes>(
        "main:runningShoes",
        "Running Shoes",
        Material::runningShoes,
        24*60*60*60,
        0.03f
    );
    registerItem<PlutoniumCaptureCell>("main:plutoniumCaptureCell");
    registerItem<MemoryChip>("main:memoryChip");
    registerItem<Backpack>("main:backpack");
}

Item* ItemRegistry::getItemByName(std::string name)
{
    return items[name];
}

void ItemRegistry::getAllStacks(std::vector<ItemStack> &stacks)
{
    for (auto &[name, item] : items)
    {
        if (item == nullptr)
        {
            continue;
        }
        
        if (name == "main:block")
        {
            continue;
        }

        stacks.push_back(ItemStack(*item));
    }

    blockRegistry.getAllStacks(stacks);
}

int ItemRegistry::getTotalItems()
{
    return (int) items.size();
}