package com.tiedup.remake.blocks;

import com.tiedup.remake.core.TiedUpMod;
import java.util.function.Supplier;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.DoubleHighBlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.DoorBlock;
import net.minecraft.world.level.block.SlabBlock;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.StairBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.material.MapColor;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegistryObject;

/**
 * Mod Blocks Registration
 *
 *
 * Handles registration of all TiedUp blocks using DeferredRegister.
 *
 * Blocks:
 * - Padded block + variants (slab, stairs, pane)
 * - Rope trap
 * - Trapped bed
 * - Cell door
 * - Kidnap bomb
 */
public class ModBlocks {

    // DeferredRegister for blocks
    public static final DeferredRegister<Block> BLOCKS =
        DeferredRegister.create(ForgeRegistries.BLOCKS, TiedUpMod.MOD_ID);

    // DeferredRegister for block items (linked to ModItems)
    public static final DeferredRegister<Item> BLOCK_ITEMS =
        DeferredRegister.create(ForgeRegistries.ITEMS, TiedUpMod.MOD_ID);

    // PADDED BLOCKS

    /**
     * Base padded block properties.
     * Cloth material, soft, quiet.
     */
    private static BlockBehaviour.Properties paddedProperties() {
        return BlockBehaviour.Properties.of()
            .mapColor(MapColor.WOOL)
            .strength(0.9f, 45.0f)
            .sound(SoundType.WOOL);
    }

    /**
     * Padded Block - Basic soft block.
     */
    public static final RegistryObject<Block> PADDED_BLOCK = registerBlock(
        "padded_block",
        () -> new Block(paddedProperties())
    );

    /**
     * Padded Slab - Half-height padded block.
     */
    public static final RegistryObject<Block> PADDED_SLAB = registerBlock(
        "padded_slab",
        () -> new SlabBlock(paddedProperties())
    );

    /**
     * Padded Stairs - Stair variant of padded block.
     */
    public static final RegistryObject<Block> PADDED_STAIRS = registerBlock(
        "padded_stairs",
        () ->
            new StairBlock(
                () -> PADDED_BLOCK.get().defaultBlockState(),
                paddedProperties()
            )
    );

    // TRAP BLOCKS

    /**
     * Rope Trap - Flat trap that ties up entities that walk on it.
     * Uses BlockEntity to store bondage items.
     */
    public static final RegistryObject<Block> ROPE_TRAP = registerBlock(
        "rope_trap",
        BlockRopeTrap::new
    );

    /**
     * Kidnap Bomb - TNT that applies bondage on explosion.
     * Uses BlockEntity to store bondage items.
     */
    public static final RegistryObject<Block> KIDNAP_BOMB = registerBlock(
        "kidnap_bomb",
        BlockKidnapBomb::new
    );

    /**
     * Trapped Chest - Chest that traps players when opened.
     * Uses BlockEntity to store bondage items.
     */
    public static final RegistryObject<Block> TRAPPED_CHEST = registerBlock(
        "trapped_chest",
        BlockTrappedChest::new
    );

    // DOOR BLOCKS

    /**
     * Cell Door - Iron-like door that requires redstone to open.
     * Cannot be opened by hand.
     */
    public static final RegistryObject<BlockCellDoor> CELL_DOOR =
        registerDoorBlock("cell_door", BlockCellDoor::new);

    // CELL SYSTEM BLOCKS

    /**
     * Marker Block - Invisible block for cell spawn points.
     * Stores cell UUID and links to CellRegistry.
     */
    public static final RegistryObject<Block> MARKER = registerBlockNoItem(
        "marker",
        BlockMarker::new
    );

    /**
     * Iron Bar Door - Lockable door made of iron bars.
     * Can be locked with keys and unlocked with matching key, cell key, or master key.
     */
    public static final RegistryObject<BlockIronBarDoor> IRON_BAR_DOOR =
        registerDoorBlock("iron_bar_door", BlockIronBarDoor::new);

    /**
     * Cell Core - Anchor block for Cell System V2.
     * Placed into a wall; runs flood-fill to detect the room and register a cell.
     */
    public static final RegistryObject<Block> CELL_CORE = registerBlock(
        "cell_core",
        BlockCellCore::new
    );

    // REGISTRATION HELPERS

    /**
     * Register a block and its corresponding BlockItem.
     *
     * @param name Block registry name
     * @param blockSupplier Block supplier
     * @return RegistryObject for the block
     */
    private static <T extends Block> RegistryObject<T> registerBlock(
        String name,
        Supplier<T> blockSupplier
    ) {
        RegistryObject<T> block = BLOCKS.register(name, blockSupplier);
        registerBlockItem(name, block);
        return block;
    }

    /**
     * Register a BlockItem for a block.
     *
     * @param name Item registry name (same as block)
     * @param block The block to create an item for
     */
    private static <T extends Block> void registerBlockItem(
        String name,
        RegistryObject<T> block
    ) {
        BLOCK_ITEMS.register(name, () ->
            new BlockItem(block.get(), new Item.Properties())
        );
    }

    /**
     * Register a block without an item.
     * Used for blocks that need special item handling (e.g., trapped bed, doors).
     *
     * @param name Block registry name
     * @param blockSupplier Block supplier
     * @return RegistryObject for the block
     */
    private static <T extends Block> RegistryObject<T> registerBlockNoItem(
        String name,
        Supplier<T> blockSupplier
    ) {
        return BLOCKS.register(name, blockSupplier);
    }

    /**
     * Register a door block with DoubleHighBlockItem.
     * Doors are double-height blocks and need special item handling.
     *
     * @param name Block registry name
     * @param blockSupplier Block supplier (must return DoorBlock or subclass)
     * @return RegistryObject for the block
     */
    private static <T extends DoorBlock> RegistryObject<T> registerDoorBlock(
        String name,
        Supplier<T> blockSupplier
    ) {
        RegistryObject<T> block = BLOCKS.register(name, blockSupplier);
        BLOCK_ITEMS.register(name, () ->
            new DoubleHighBlockItem(block.get(), new Item.Properties())
        );
        return block;
    }
}
