/*
 *  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.core.device;

import net.minecraft.world.entity.EntityType;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import top.r3944realms.eroticdungeongame.content.animation.EDGAnimation;
import top.r3944realms.eroticdungeongame.content.block.FurnitureShapeType;
import top.r3944realms.eroticdungeongame.content.block.type.*;
import top.r3944realms.eroticdungeongame.content.entity.SeatEntity;
import top.r3944realms.eroticdungeongame.core.register.EDGEntities;

import java.util.Map;
import java.util.WeakHashMap;

@SuppressWarnings("unused")
public enum SeatType implements ISeatType {
    CUFF_BED(FurnitureShapeType.HORIZONTAL_DOUBLE, "cuff_bed", CuffBedBlock.class,  -0.5d, -0.2d, 0.75d, false,new AABB(0,0,0, 1,1, 1), 0.25f, new Vec3(0, 0, -0.2)),
    IRON_CAGE(FurnitureShapeType.VERTICAL_DOUBLE, "iron_cage", IronCageBlock.class, -0.5d, -0.1d, 0.5d, false),
    RACK(FurnitureShapeType.HORIZONTAL_TRIPLE, "rack", RackBlock.class,-0.5d, 0.0d, 1.4d, false, new AABB(0,0,0, 1,1, 1), 0.25f),
    CRUX(FurnitureShapeType.CRUX, "crux", CruxBlock.class,0.5d, -0.15d, -0.8d, true, new AABB(0,0,0,0.32,1.85,0.32), new Vec3(0, 0, -0.2)),
    PETRINE_CROSS(FurnitureShapeType.PETRINE_CROSS, "petrine_cross", PetrineCrossBlock.class,0.5d, -0.2d, -0.8d, true, new AABB(0,0,0,0.32,1.85,0.32), new Vec3(0, 0, -0.2)),
    X_CROSS(FurnitureShapeType.VERTICAL_DOUBLE, "x_cross", XCrossBlock.class,0.5d, -0.15d, -0.8d, true, new AABB(0,0,0,0.32,1.85,0.32), new Vec3(0, 0, -0.2)),
    SPANISH_DONKEY(FurnitureShapeType.NORMAL, "spanish_donkey", SpanishDonkeyBlock.class, -0.5d, 0.1d, 0.5d, 90.0f, false, 0.75f, new Vec3(-0.25, 0, 0)),
    PILLORY(FurnitureShapeType.VERTICAL_DOUBLE, "pillory", PilloryBlock.class, -0.5d, -0.2d, 1.05d, false, new AABB(0,0,0,0.4,1.25,0.4), 0.65f),
    WALL_RACK(FurnitureShapeType.OVERRIDE_VERTICAL_TRIPLE, "wall_rack", WallRackBlock.class, 0.5d, -1.5d, -0.8d, true, new AABB(0,0,0,0.32,1.85,0.32), new Vec3(0, 0, -0.2)),
    CUFF_POLE(FurnitureShapeType.VERTICAL_DOUBLE, "cuff_pole", CuffPoleBlock.class, 0.5d, -0.1d, -0.3d, true, new Vec3(0, 0, -0.2)),
    PRONE_BENCH(FurnitureShapeType.NORMAL, "prone_bench", ProneBenchBlock.class, 0.5d, 0.10d, -0.7d, true, new AABB(0,0,0, 1,1, 1), new Vec3(0, 0, -0.2)),
    HANGING_POST(FurnitureShapeType.VERTICAL_TRIPLE, "hanging_post", HangingPostBlock.class, 0.5d, 0.0d, -0.2d, true, new AABB(0,0,0, 1,2, 1), new Vec3(0, 0, -0.1)),
    ;
    private final String name;
    private final Class<?> blockClass;
    private final double offsetX;
    private final double offsetY;
    private final double offsetZ;
    private final Vec3 fMOffset;

    private final float yawOffset;
    private final AABB playerBB;
    private final float eyeHeight;

    public final Map<ISeatType, EDGAnimation> cache = new WeakHashMap<>();

    public static final SeatTypeRegistry REGISTRY = new SeatTypeRegistry();

    private static void register(ISeatType seatType) {
        REGISTRY.register(seatType, EDGEntities.SEAT);
    }

    static {
        register(CUFF_BED);
        register(IRON_CAGE);
        register(RACK);
        register(SPANISH_DONKEY);
        register(CRUX);
        register(PETRINE_CROSS);
        register(X_CROSS);
        register(PILLORY);
        register(WALL_RACK);
        register(CUFF_POLE);
        register(PRONE_BENCH);
        register(HANGING_POST);
    }

    @Override
    public FurnitureShapeType getFurnitureShapeType() {
        return furnitureShapeType;
    }

    @Override
    public boolean isOppositeDirection() {
        return isOppositeDirection;
    }

    @Override
    public Vec3 getFirstModelOffset() {
        return fMOffset;
    }

    @Override
    public double getOffsetZ() {
        return offsetZ;
    }

    @Override
    public double getOffsetY() {
        return offsetY;
    }

    @Override
    public double getOffsetX() {
        return offsetX;
    }

    @Override
    public Class<?> getBlockClass() {
        return blockClass;
    }

    @Override
    public float getYawOffset() {
        return yawOffset;
    }

    @Override
    public float getEyeHeight() {
        return eyeHeight;
    }

    @Override
    public AABB getPlayerBB() {
        return playerBB;
    }

    @Override
    public @Nullable EDGAnimation getAnimation() {
        EDGAnimation edgAnimation = cache.get(this);
        if (edgAnimation == null) {
            EDGAnimation animation = EDGAnimation.getAnimation(blockClass);
            if (animation != null) {
                cache.put(this, animation);
                return animation;
            } return null;
        }
        return edgAnimation;
    }

    @Override
    @Contract()
    public @NotNull String getName() {
        return name + "_seat";
    }

    /**
     * 获取座位对应的实体类型
     */
    @Override
    public @NotNull EntityType<SeatEntity> getEntityType() {
        return REGISTRY.getEntityType(this);
    }


    private final boolean isOppositeDirection;
    private final FurnitureShapeType furnitureShapeType;

    SeatType(FurnitureShapeType furnitureType, String name, Class<?> blockClass, double offsetX, double offsetY, double offsetZ, boolean isOppositeDirection) {
        this(furnitureType, name, blockClass, offsetX, offsetY, offsetZ, 0, isOppositeDirection, null, -1, Vec3.ZERO);
    }

    SeatType(FurnitureShapeType furnitureType, String name, Class<?> blockClass, double offsetX, double offsetY, double offsetZ, float yawOffset, boolean isOppositeDirection) {
        this(furnitureType, name, blockClass, offsetX, offsetY, offsetZ, yawOffset, isOppositeDirection, null, -1, Vec3.ZERO);
    }

    SeatType(FurnitureShapeType furnitureType, String name, Class<?> blockClass, double offsetX, double offsetY, double offsetZ, boolean isOppositeDirection, AABB playerBB, float eyeHeight) {
        this(furnitureType, name, blockClass, offsetX, offsetY, offsetZ, 0, isOppositeDirection, playerBB, eyeHeight, Vec3.ZERO);
    }

    SeatType(FurnitureShapeType furnitureType, String name, Class<?> blockClass, double offsetX, double offsetY, double offsetZ, float yawOffset, boolean isOppositeDirection, AABB playerBB) {
        this(furnitureType, name, blockClass, offsetX, offsetY, offsetZ, yawOffset, isOppositeDirection, playerBB, -1, Vec3.ZERO);
    }

    SeatType(FurnitureShapeType furnitureType, String name, Class<?> blockClass, double offsetX, double offsetY, double offsetZ, boolean isOppositeDirection, AABB playerBB) {
        this(furnitureType, name, blockClass, offsetX, offsetY, offsetZ, 0, isOppositeDirection, playerBB, -1, Vec3.ZERO);
    }

    SeatType(FurnitureShapeType furnitureType, String name, Class<?> blockClass, double offsetX, double offsetY, double offsetZ, float yawOffset, boolean isOppositeDirection, float eyeHeight) {
        this(furnitureType, name, blockClass, offsetX, offsetY, offsetZ, yawOffset, isOppositeDirection, null, eyeHeight, Vec3.ZERO);
    }

    SeatType(FurnitureShapeType furnitureType, String name, Class<?> blockClass, double offsetX, double offsetY, double offsetZ, boolean isOppositeDirection, float eyeHeight) {
        this(furnitureType, name, blockClass, offsetX, offsetY, offsetZ, 0, isOppositeDirection, null, eyeHeight, Vec3.ZERO);
    }

    SeatType(FurnitureShapeType furnitureType, String name, Class<?> blockClass, double offsetX, double offsetY, double offsetZ, float yawOffset, boolean isOppositeDirection, AABB playerBB, float eyeHeight) {
        this(furnitureType, name, blockClass, offsetX, offsetY, offsetZ, yawOffset, isOppositeDirection, playerBB, eyeHeight, Vec3.ZERO);
    }

    SeatType(FurnitureShapeType furnitureType, String name, Class<?> blockClass, double offsetX, double offsetY, double offsetZ, boolean isOppositeDirection, Vec3 fMOffset) {
        this(furnitureType, name, blockClass, offsetX, offsetY, offsetZ, 0, isOppositeDirection, null, -1, fMOffset);
    }

    SeatType(FurnitureShapeType furnitureType, String name, Class<?> blockClass, double offsetX, double offsetY, double offsetZ, float yawOffset, boolean isOppositeDirection, Vec3 fMOffset) {
        this(furnitureType, name, blockClass, offsetX, offsetY, offsetZ, yawOffset, isOppositeDirection, null, -1, fMOffset);
    }

    SeatType(FurnitureShapeType furnitureType, String name, Class<?> blockClass, double offsetX, double offsetY, double offsetZ, boolean isOppositeDirection, AABB playerBB, float eyeHeight, Vec3 fMOffset) {
        this(furnitureType, name, blockClass, offsetX, offsetY, offsetZ, 0, isOppositeDirection, playerBB, eyeHeight, fMOffset);
    }

    SeatType(FurnitureShapeType furnitureType, String name, Class<?> blockClass, double offsetX, double offsetY, double offsetZ, boolean isOppositeDirection, AABB playerBB, Vec3 fMOffset) {
        this(furnitureType, name, blockClass, offsetX, offsetY, offsetZ, 0, isOppositeDirection, playerBB, -1, fMOffset);
    }

    SeatType(FurnitureShapeType furnitureType, String name, Class<?> blockClass, double offsetX, double offsetY, double offsetZ, float yawOffset, boolean isOppositeDirection, float eyeHeight, Vec3 fMOffset) {
        this(furnitureType, name, blockClass, offsetX, offsetY, offsetZ, yawOffset, isOppositeDirection, null, eyeHeight, fMOffset);
    }

    SeatType(FurnitureShapeType furnitureType, String name, Class<?> blockClass, double offsetX, double offsetY, double offsetZ, boolean isOppositeDirection, float eyeHeight, Vec3 fMOffset) {
        this(furnitureType, name, blockClass, offsetX, offsetY, offsetZ, 0, isOppositeDirection, null, eyeHeight, fMOffset);
    }

    // 主构造函数 - 添加 fMOffset 参数
    SeatType(FurnitureShapeType furnitureType, String name, Class<?> blockClass, double offsetX, double offsetY, double offsetZ, float yawOffset, boolean isOppositeDirection, AABB playerBB, float eyeHeight, Vec3 fMOffset) {
        this.name = name;
        this.blockClass = blockClass;
        this.offsetX = offsetX;
        this.offsetY = offsetY;
        this.offsetZ = offsetZ;
        this.yawOffset = yawOffset;
        this.isOppositeDirection = isOppositeDirection;
        this.furnitureShapeType = furnitureType;
        this.playerBB = playerBB;
        this.eyeHeight = eyeHeight;
        this.fMOffset = fMOffset; // 初始化 fMOffset
    }
}
