/*
 *  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.mixin.minecraft;

import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.AABB;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import top.r3944realms.eroticdungeongame.api.workspace.Services;
import top.r3944realms.eroticdungeongame.content.block.blockentity.BaseSeatBlockEntity;
import top.r3944realms.eroticdungeongame.content.entity.SeatEntity;
import top.r3944realms.eroticdungeongame.core.service.SeatService;
import top.r3944realms.eroticdungeongame.util.BoundingBoxCalculator;
import top.r3944realms.eroticdungeongame.util.IEDGEntity;

import javax.annotation.Nullable;
import java.util.Objects;
import java.util.Optional;

@Mixin(Entity.class)
public abstract class MixinEntity implements IEDGEntity {

    @Shadow @Nullable public abstract Entity getVehicle();

    @Shadow private Level level;

    @Shadow public abstract void stopRiding();

    @Shadow @Nullable private Entity vehicle;

    @Shadow public abstract void removeVehicle();

    @Shadow public abstract void playerTouch(Player player);

    @WrapMethod(
            method = "getBoundingBox"
    )
    private AABB redefinedBoundingBox(@NotNull Operation<AABB> original){
        Entity self = Entity.class.cast(this);
        return Services.WORK_SPACE.tryToDoIfInDeviceAndRet(self, data-> {
            AABB playerBoundingBox = data.getPlayerBoundingBox();
            if (playerBoundingBox != null) {
                return BoundingBoxCalculator.positionBoundingBox(playerBoundingBox, self.position());
            } else return original.call();
        }, original::call);
    }

    @WrapMethod(
            method = "startRiding(Lnet/minecraft/world/entity/Entity;Z)Z"
    )
    private boolean redefineStartRiding(Entity vehicle, boolean force, Operation<Boolean> original) {
        Entity entity = Entity.class.cast(this);
        return Services.WORK_SPACE.tryToDoIfInDeviceAndRet(entity,
                data -> {
                    if (data.getDeviceMainBlockPos() != null && level.getBlockEntity(data.getDeviceMainBlockPos()) instanceof BaseSeatBlockEntity seatBe && seatBe.hasLockCode()) {
                        if (entity instanceof Player player && SeatService.getPlayerSeat(player).isPresent()) {
                            return false;
                        }
                    }
                    return original.call(vehicle, force);
                },
                () -> original.call(vehicle, force)
        );
    }

    @WrapMethod(
            method = "stopRiding"
    )
    private void redefineStopRiding(Operation<Void> original) {
          Entity entity = Entity.class.cast(this);
        Services.WORK_SPACE.tryToDoIfInDevice(entity,
                data -> {
                    if (data.getDeviceMainBlockPos() == null || !(level.getBlockEntity(data.getDeviceMainBlockPos()) instanceof BaseSeatBlockEntity seatBe) || !seatBe.hasLockCode()) {
                        original.call();
                    } else if (entity instanceof Player player) {
                        Optional<SeatEntity> playerSeat = SeatService.getPlayerSeat(player);
                        if (playerSeat.isEmpty() || playerSeat.get().isRemoved()) {
                            original.call();
                        }
                    }
                },
                original::call
        );
    }


    @SuppressWarnings("AddedMixinMembersNamePattern")
    @Override
    public void releaseEntityFromEDGDevice(long lock) {
        Services.WORK_SPACE.tryToDoIfInDevice(Entity.class.cast(this),
                data -> {
                    if (data.getDeviceMainBlockPos() != null && level.getBlockEntity(data.getDeviceMainBlockPos()) instanceof BaseSeatBlockEntity seatBe) {
                        if ((Entity.class.cast(this) instanceof Player player && player.isCreative()) || (seatBe.hasLockCode() && Objects.equals(seatBe.getLockCode(), lock)) || !seatBe.hasLockCode()) {
                            removeVehicle();
                        }
                    }
                }
        );
    }

}
