package ovh.glitchlabs.ornamentum.blocks.custom;

import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.phys.BlockHitResult;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashSet;
import java.util.Set;

/**
 * A block that can be toggled on/off via shift-right-click.
 * Toggling propagates through directly adjacent FanBlocks (BFS / flood-fill),
 * similar to how a redstone wire network shares state.
 */
public class FanBlock extends Block {

    public static final BooleanProperty ON = BooleanProperty.create("on");

    // Safety cap so an absurdly large network can't cause a huge single-tick update.
    private static final int MAX_NETWORK_SIZE = 4096;

    public FanBlock(Properties properties) {
        super(properties);
        this.registerDefaultState(this.stateDefinition.any().setValue(ON, false));
    }

    @Override
    protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
        builder.add(ON);
    }

    @Override
    protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) {
        if (player.isShiftKeyDown()) {
            if (!level.isClientSide) {
                toggleNetwork(level, pos, !state.getValue(ON));
            }
            return InteractionResult.SUCCESS;
        }
        return InteractionResult.PASS;
    }

    /**
     * Flood-fills outward from {@code origin} through orthogonally adjacent FanBlocks
     * and sets all of them to {@code newState}.
     */
    private void toggleNetwork(Level level, BlockPos origin, boolean newState) {
        Set<BlockPos> visited = new HashSet<>();
        Deque<BlockPos> queue = new ArrayDeque<>();

        visited.add(origin.immutable());
        queue.add(origin);

        while (!queue.isEmpty() && visited.size() <= MAX_NETWORK_SIZE) {
            BlockPos pos = queue.poll();
            BlockState state = level.getBlockState(pos);

            if (!(state.getBlock() instanceof FanBlock)) {
                continue;
            }

            if (state.getValue(ON) != newState) {
                level.setBlock(pos, state.setValue(ON, newState), Block.UPDATE_ALL);
            }

            for (Direction direction : Direction.values()) {
                BlockPos neighborPos = pos.relative(direction);
                if (visited.contains(neighborPos)) {
                    continue;
                }

                BlockState neighborState = level.getBlockState(neighborPos);
                if (neighborState.getBlock() instanceof FanBlock) {
                    visited.add(neighborPos.immutable());
                    queue.add(neighborPos);
                }
            }
        }
    }
}
