/*
 *  Copyright 2025-2026 R3944Realms
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package top.r3944realms.eroticdungeongame.content.block;

import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;

public enum FurnitureShapeType {
    NORMAL {
        @Override
        public BlockPos[] getAllPositions(Level level, BlockState primeBs, BlockPos primePos) {
            return new BlockPos[]{primePos};
        }
    },
    HORIZONTAL_DOUBLE {
        @Override
        public BlockPos[] getAllPositions(Level level, BlockState primeBs, BlockPos primePos) {
            List<BlockPos> positions = new ArrayList<>();
            positions.add(primePos);

            // 检查第二个部件位置
            BlockPos secondPos = primePos.relative(primeBs.getValue(AbstractSeatBlock.FACING));
            addIfSameBlock(level, positions, primeBs.getBlock(), secondPos);

            return positions.toArray(new BlockPos[0]);
        }
    },
    HORIZONTAL_TRIPLE {
        @Override
        public BlockPos[] getAllPositions(Level level, BlockState primeBs, BlockPos primePos) {
            List<BlockPos> positions = new ArrayList<>();
            Direction facing = primeBs.getValue(AbstractSeatBlock.FACING);
            Block targetBlock = primeBs.getBlock();

            positions.add(primePos);
            addIfSameBlock(level, positions, targetBlock, primePos.relative(facing));      // MIDDLE
            addIfSameBlock(level, positions, targetBlock, primePos.relative(facing, 2));    // HEAD

            return positions.toArray(new BlockPos[0]);
        }
    },
    VERTICAL_DOUBLE {
        @Override
        public BlockPos[] getAllPositions(Level level, BlockState primeBs, BlockPos primePos) {
            List<BlockPos> positions = new ArrayList<>();
            positions.add(primePos);
            addIfSameBlock(level, positions, primeBs.getBlock(), primePos.above());
            return positions.toArray(new BlockPos[0]);
        }
    },
    VERTICAL_TRIPLE {
        @Override
        public BlockPos[] getAllPositions(Level level, BlockState primeBs, BlockPos primePos) {
            List<BlockPos> positions = new ArrayList<>();
            Block targetBlock = primeBs.getBlock();

            positions.add(primePos);
            addIfSameBlock(level, positions, targetBlock, primePos.above());      // MIDDLE
            addIfSameBlock(level, positions, targetBlock, primePos.above(2));     // HEAD

            return positions.toArray(new BlockPos[0]);
        }
    },
    OVERRIDE_VERTICAL_TRIPLE {
        @Override
        public BlockPos[] getAllPositions(Level level, BlockState primeBs, BlockPos primePos) {
            List<BlockPos> positions = new ArrayList<>();
            Direction facing = primeBs.getValue(AbstractSeatBlock.FACING);
            Block targetBlock = primeBs.getBlock();

            positions.add(primePos);
            addIfSameBlock(level, positions, targetBlock, primePos.relative(facing.getClockWise()));         // 右边
            addIfSameBlock(level, positions, targetBlock, primePos.relative(facing.getCounterClockWise()));  // 左边

            return positions.toArray(new BlockPos[0]);
        }
    },
    CRUX {
        @Override
        public BlockPos[] getAllPositions(Level level, BlockState primeBs, BlockPos primePos) {
            List<BlockPos> positions = new ArrayList<>();
            Direction facing = primeBs.getValue(AbstractSeatBlock.FACING);
            Block targetBlock = primeBs.getBlock();

            positions.add(primePos);

            BlockPos above = primePos.above();
            addIfSameBlock(level, positions, targetBlock, above);                    // 上面
            addIfSameBlock(level, positions, targetBlock, above.relative(facing.getClockWise()));         // 右上
            addIfSameBlock(level, positions, targetBlock, above.relative(facing.getCounterClockWise()));  // 左上

            return positions.toArray(new BlockPos[0]);
        }
    },
    PETRINE_CROSS {
        @Override
        public BlockPos[] getAllPositions(Level level, BlockState primeBs, BlockPos primePos) {
            List<BlockPos> positions = new ArrayList<>();
            Direction facing = primeBs.getValue(AbstractSeatBlock.FACING);
            Block targetBlock = primeBs.getBlock();

            positions.add(primePos);
            addIfSameBlock(level, positions, targetBlock, primePos.above());                              // 上面
            addIfSameBlock(level, positions, targetBlock, primePos.relative(facing.getClockWise()));     // 右边
            addIfSameBlock(level, positions, targetBlock, primePos.relative(facing.getCounterClockWise())); // 左边

            return positions.toArray(new BlockPos[0]);
        }
    },
        HOLLOW_FRAME_3x3 {
            @Override
            public BlockPos[] getAllPositions(Level level, BlockState primeBs, BlockPos primePos) {
                List<BlockPos> positions = new ArrayList<>();
                Block targetBlock = primeBs.getBlock();

                positions.add(primePos);

                // 获取所有理论位置并批量检查
                BlockPos[] theoreticalPositions = getTheoreticalPositions(primeBs, primePos);
                addAllIfSameBlock(level, positions, targetBlock, theoreticalPositions);

                return positions.toArray(new BlockPos[0]);
            }
        };

    /**
     * 获取从主部件开始的所有相连部件位置
     * 参数传入的总是主部件（FOOT部件）的位置
     * 如果某个部件不是相同的方块类型，则停止查找并返回已找到的位置
     *
     * @param level 世界
     * @param primeBs 主部件的方块状态
     * @param primePos 主部件的位置
     * @return 所有相连的部件位置数组
     */
    public abstract BlockPos[] getAllPositions(Level level, BlockState primeBs, BlockPos primePos);

    /**
     * 获取理论上的所有位置（不考虑实际是否存在对应方块）
     */
    public BlockPos[] getTheoreticalPositions(BlockState primeBs, BlockPos primePos) {
        final Direction direction = primeBs.getValue(AbstractSeatBlock.FACING);
        final Direction counterClockWise = direction.getCounterClockWise();
        return switch (this) {
            case NORMAL -> new BlockPos[]{primePos};
            case HORIZONTAL_DOUBLE -> new BlockPos[]{
                    primePos,
                    primePos.relative(direction)
            };
            case HORIZONTAL_TRIPLE -> new BlockPos[]{
                    primePos,
                    primePos.relative(direction),
                    primePos.relative(direction, 2)
            };
            case VERTICAL_DOUBLE -> new BlockPos[]{
                    primePos,
                    primePos.above()
            };
            case VERTICAL_TRIPLE -> new BlockPos[]{
                    primePos,
                    primePos.above(),
                    primePos.above(2)
            };
            case OVERRIDE_VERTICAL_TRIPLE -> new BlockPos[]{
                    primePos,
                    primePos.relative(direction.getClockWise()),
                    primePos.relative(counterClockWise)
            };
            case CRUX -> {
                BlockPos above = primePos.above();
                yield new BlockPos[]{
                        primePos,
                        above,
                        above.relative(direction.getClockWise()),
                        above.relative(counterClockWise)
                };
            }
            case PETRINE_CROSS -> new BlockPos[] {
                    primePos,
                    primePos.above(),
                    primePos.relative(direction.getClockWise()),
                    primePos.relative(counterClockWise)
            };
            case HOLLOW_FRAME_3x3 -> {
                BlockPos below2 = primePos.below(2);
                BlockPos below = primePos.below();
                Direction opposite = counterClockWise.getOpposite();
                yield new BlockPos[] {
                        below2.relative(opposite),
                        below2,
                        below2.relative(counterClockWise),
                        below.relative(opposite),
                        below.relative(counterClockWise),
                        primePos.relative(opposite),
                        primePos.relative(counterClockWise),
                        primePos
                };
            }
        };
    }

    /**
     * 检查是否所有部件都存在
     */
    public boolean hasAllParts(Level level, BlockState pBlockState, BlockPos pBlockPos) {
        BlockPos[] theoretical = getTheoreticalPositions(pBlockState, pBlockPos);
        Block currentBlock = pBlockState.getBlock();

        for (BlockPos pos : theoretical) {
            if (level.getBlockState(pos).getBlock() != currentBlock) {
                return false;
            }
        }
        return true;
    }

    /**
     * 获取实际存在的部件数量
     */
    public int getExistingPartCount(Level level, BlockState pBlockState, BlockPos pBlockPos) {
        BlockPos[] positions = getAllPositions(level, pBlockState, pBlockPos);
        return positions.length;
    }

    private static void addIfSameBlock(@NotNull Level level, List<BlockPos> positions, Block targetBlock, BlockPos pos) {
        if (level.getBlockState(pos).getBlock() == targetBlock) {
            positions.add(pos);
        }
    }
    private static void addAllIfSameBlock(Level level, List<BlockPos> positions, Block targetBlock, BlockPos @NotNull ... posArray) {
        for (BlockPos pos : posArray) {
            if (level.getBlockState(pos).getBlock() == targetBlock) {
                positions.add(pos);
            }
        }
    }
}