/*
 *  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 com.mojang.authlib.GameProfile;
import net.minecraft.core.BlockPos;
import net.minecraft.network.protocol.game.ClientboundRemoveMobEffectPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
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.IEDGEntity;

import java.util.Objects;
import java.util.Optional;

@Mixin(ServerPlayer.class)
public abstract class MixinServerPlayer extends Player implements IEDGEntity {
    public MixinServerPlayer(Level level, BlockPos pos, float yRot, GameProfile gameProfile) {
        super(level, pos, yRot, gameProfile);
    }

    @Shadow public abstract ServerLevel serverLevel();

    @Shadow public ServerGamePacketListenerImpl connection;

    @Shadow public abstract boolean isCreative();

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

    @SuppressWarnings("AddedMixinMembersNamePattern")
    @Override
    public void releaseEntityFromEDGDevice(long lock) {
        ServerPlayer player = ServerPlayer.class.cast(this);
        Services.WORK_SPACE.tryToDoIfInDevice(player,
                data -> {
                    if (data.getDeviceMainBlockPos() != null && level().getBlockEntity(data.getDeviceMainBlockPos()) instanceof BaseSeatBlockEntity seatBe) {
                        if (isCreative() || (seatBe.hasLockCode() && Objects.equals(seatBe.getLockCode(), lock)) || !seatBe.hasLockCode()) {
                            Entity entity = this.getVehicle();
                            this.removeVehicle();
                            if (entity != null && entity != this.getVehicle() && !this.level().isClientSide) {
                                Vec3 vec3;
                                if (this.isRemoved()) {
                                    vec3 = this.position();
                                } else if (!entity.isRemoved() && !this.level().getBlockState(entity.blockPosition()).is(BlockTags.PORTALS)) {
                                    vec3 = entity.getDismountLocationForPassenger(this);
                                } else {
                                    double d0 = Math.max(this.getY(), entity.getY());
                                    vec3 = new Vec3(this.getX(), d0, this.getZ());
                                }

                                this.dismountTo(vec3.x, vec3.y, vec3.z);
                            }
                            if (entity instanceof LivingEntity livingentity) {
                                for (MobEffectInstance mobeffectinstance : livingentity.getActiveEffects()) {
                                    connection.send(new ClientboundRemoveMobEffectPacket(entity.getId(), mobeffectinstance.getEffect()));
                                }
                            }
                        }
                    }
                }
        );
    }

}
