package ru.dbotthepony.mc.otm.shapes;

import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.Direction;
import net.minecraft.world.phys.shapes.BooleanOp;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import ru.dbotthepony.mc.otm.core.math.BlockRotation;

import javax.annotation.ParametersAreNonnullByDefault;

@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public record BlockShape(SimpleCuboid ...shapes) {
	public BlockShape moveY(final double value) {
		var list = new SimpleCuboid[shapes.length];

		for (int i = 0; i < shapes.length; i++)
			list[i] = shapes[i].moveY(value);

		return new BlockShape(list);
	}

	public BlockShape rotateAroundY(double rad) {
		var list = new SimpleCuboid[shapes.length];

		for (int i = 0; i < shapes.length; i++)
			list[i] = shapes[i].rotateAroundY(rad);

		return new BlockShape(list);
	}

	public BlockShape rotateAroundX(double rad) {
		var list = new SimpleCuboid[shapes.length];

		for (int i = 0; i < shapes.length; i++)
			list[i] = shapes[i].rotateAroundX(rad);

		return new BlockShape(list);
	}

	public BlockShape rotateAroundZ(double rad) {
		var list = new SimpleCuboid[shapes.length];

		for (int i = 0; i < shapes.length; i++)
			list[i] = shapes[i].rotateAroundZ(rad);

		return new BlockShape(list);
	}

	public BlockShape rotateFromSouth(Direction dir) {
		if (dir == Direction.SOUTH)
			return this;

		if (dir == Direction.NORTH)
			return rotateAroundY(Math.PI);

		if (dir == Direction.WEST)
			return rotateAroundY(-Math.PI / 2d);

		if (dir == Direction.EAST)
			return rotateAroundY(Math.PI / 2d);

		if (dir == Direction.UP)
			return rotateAroundX(Math.PI / 2d);

		if (dir == Direction.DOWN)
			return rotateAroundX(-Math.PI / 2d);

		return this;
	}

	public BlockShape rotateFromNorth(Direction dir) {
		if (dir == Direction.SOUTH)
			return rotateAroundY(Math.PI);

		if (dir == Direction.NORTH)
			return this;

		if (dir == Direction.WEST)
			return rotateAroundY(-Math.PI / 2d);

		if (dir == Direction.EAST)
			return rotateAroundY(Math.PI / 2d);

		if (dir == Direction.UP)
			return rotateAroundX(-Math.PI / 2d);

		if (dir == Direction.DOWN)
			return rotateAroundX(Math.PI / 2d);

		return this;
	}

	public BlockShape rotateFromNorth(BlockRotation dir) {
		var result = rotateFromNorth(dir.getFront());

		if (dir.getTop() != Direction.DOWN && dir.getTop() != Direction.UP)
			result = result.rotateFromNorth(dir.getTop());

		return result;
	}

	public BlockShape rotateFromSouth(BlockRotation dir) {
		var result = rotateFromSouth(dir.getFront());

		if (dir.getTop() != Direction.DOWN && dir.getTop() != Direction.UP)
			result = result.rotateFromSouth(dir.getTop());

		return result;
	}

	public VoxelShape computeShape() {
		VoxelShape final_shape = shapes[0].getShape();

		for (int i = 1; i < shapes.length; i++)
			final_shape = Shapes.join(final_shape, shapes[i].getShape(), BooleanOp.OR);

		return final_shape;
	}
}
