package com.straice.smoothdoors.util;

import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.DoorBlock;
import net.minecraft.block.FenceGateBlock;
import net.minecraft.block.TrapdoorBlock;
import net.minecraft.block.enums.BlockHalf;
import net.minecraft.block.enums.DoorHinge;
import net.minecraft.block.enums.DoubleBlockHalf;
import net.minecraft.state.property.Properties;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;

public final class ConnectedUtil {
    private ConnectedUtil() {}

    // ===== DOORS =====

    public static BlockPos getDoorLowerPos(BlockPos pos, BlockState state) {
        DoubleBlockHalf half = state.get(Properties.DOUBLE_BLOCK_HALF);
        return half == DoubleBlockHalf.LOWER ? pos : pos.down();
    }

    public static BlockPos findPairedDoorLower(World world, BlockPos lowerPos, BlockState lowerState) {
        if (!(lowerState.getBlock() instanceof DoorBlock)) return null;

        Direction facing = lowerState.get(Properties.HORIZONTAL_FACING);
        DoorHinge hinge = lowerState.get(Properties.DOOR_HINGE);

        Direction side = (hinge == DoorHinge.LEFT)
                ? facing.rotateYClockwise()
                : facing.rotateYCounterclockwise();

        BlockPos otherLower = lowerPos.offset(side);
        BlockState other = world.getBlockState(otherLower);

        if (other.getBlock() != lowerState.getBlock()) return null;
        if (!(other.getBlock() instanceof DoorBlock)) return null;
        if (other.get(Properties.DOUBLE_BLOCK_HALF) != DoubleBlockHalf.LOWER) return null;
        if (other.get(Properties.HORIZONTAL_FACING) != facing) return null;
        if (other.get(Properties.DOOR_HINGE) == hinge) return null;

        return otherLower;
    }

    public static void setDoorOpen(World world, BlockPos doorLower, boolean open) {
        BlockState lower = world.getBlockState(doorLower);
        if (!(lower.getBlock() instanceof DoorBlock)) return;

        BlockPos upperPos = doorLower.up();
        BlockState upper = world.getBlockState(upperPos);

        world.setBlockState(doorLower, lower.with(Properties.OPEN, open), Block.NOTIFY_LISTENERS);

        if (upper.getBlock() == lower.getBlock()) {
            world.setBlockState(upperPos, upper.with(Properties.OPEN, open), Block.NOTIFY_LISTENERS);
        }
    }

    // ===== TRAPDOORS =====

    public static BlockPos findPairedTrapdoor(World world, BlockPos pos, BlockState state) {
        if (!(state.getBlock() instanceof TrapdoorBlock)) return null;

        Direction facing = state.get(Properties.HORIZONTAL_FACING);
        BlockHalf half = state.get(Properties.BLOCK_HALF);

        BlockPos left = pos.offset(facing.rotateYCounterclockwise());
        BlockPos right = pos.offset(facing.rotateYClockwise());

        BlockPos mate = matchTrapdoor(world, state, left, facing, half);
        if (mate != null) return mate;
        return matchTrapdoor(world, state, right, facing, half);
    }

    private static BlockPos matchTrapdoor(World world, BlockState a, BlockPos candidate, Direction facing, BlockHalf half) {
        BlockState b = world.getBlockState(candidate);
        if (b.getBlock() != a.getBlock()) return null;
        if (!(b.getBlock() instanceof TrapdoorBlock)) return null;

        if (b.get(Properties.HORIZONTAL_FACING) != facing) return null;
        if (b.get(Properties.BLOCK_HALF) != half) return null;

        return candidate;
    }

    public static void setTrapdoorOpen(World world, BlockPos pos, boolean open) {
        BlockState st = world.getBlockState(pos);
        if (!(st.getBlock() instanceof TrapdoorBlock)) return;

        world.setBlockState(pos, st.with(Properties.OPEN, open), Block.NOTIFY_LISTENERS);
    }

    // ===== FENCE GATES =====

    public static BlockPos findPairedFenceGate(World world, BlockPos pos, BlockState state) {
        if (!(state.getBlock() instanceof FenceGateBlock)) return null;

        Direction facing = state.get(Properties.HORIZONTAL_FACING);

        BlockPos left = pos.offset(facing.rotateYCounterclockwise());
        BlockPos right = pos.offset(facing.rotateYClockwise());

        BlockPos mate = matchFenceGate(world, state, left, facing);
        if (mate != null) return mate;
        return matchFenceGate(world, state, right, facing);
    }

    private static BlockPos matchFenceGate(World world, BlockState a, BlockPos candidate, Direction facing) {
        BlockState b = world.getBlockState(candidate);
        if (b.getBlock() != a.getBlock()) return null;
        if (!(b.getBlock() instanceof FenceGateBlock)) return null;

        if (b.get(Properties.HORIZONTAL_FACING) != facing) return null;
        return candidate;
    }

    public static void setFenceGateOpen(World world, BlockPos pos, boolean open) {
        BlockState st = world.getBlockState(pos);
        if (!(st.getBlock() instanceof FenceGateBlock)) return;

        world.setBlockState(pos, st.with(Properties.OPEN, open), Block.NOTIFY_LISTENERS);
    }
}
