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

import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.MenuScreens;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.WoodType;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.*;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.eroticdungeongame.EroticDungeon;
import top.r3944realms.eroticdungeongame.api.workspace.Services;
import top.r3944realms.eroticdungeongame.client.EDGKeyBindings;
import top.r3944realms.eroticdungeongame.client.gui.screens.DungeonCraftingScreen;
import top.r3944realms.eroticdungeongame.client.model.EDGArmPose;
import top.r3944realms.eroticdungeongame.client.renderer.block.IronCageBlockRenderer;
import top.r3944realms.eroticdungeongame.client.renderer.block.LoveMachineBlockRenderer;
import top.r3944realms.eroticdungeongame.client.renderer.block.SpanishDonkeyBlockRenderer;
import top.r3944realms.eroticdungeongame.client.renderer.entity.EmptySeatRenderer;
import top.r3944realms.eroticdungeongame.content.block.ISeatBlock;
import top.r3944realms.eroticdungeongame.content.block.blockentity.LoveMachineBlockEntity;
import top.r3944realms.eroticdungeongame.content.block.blockentity.SpanishDonkeyBlockEntity;
import top.r3944realms.eroticdungeongame.content.block.type.LoveMachineBlock;
import top.r3944realms.eroticdungeongame.content.block.type.SpanishDonkeyBlock;
import top.r3944realms.eroticdungeongame.content.entity.SeatEntity;
import top.r3944realms.eroticdungeongame.content.item.DeviceKeyItem;
import top.r3944realms.eroticdungeongame.content.particle.VerticalWhipSweepParticle;
import top.r3944realms.eroticdungeongame.content.particle.WhipScarParticle;
import top.r3944realms.eroticdungeongame.core.network.EDGNetworkHandler;
import top.r3944realms.eroticdungeongame.core.network.toServer.RequestQuitDevicePacket;
import top.r3944realms.eroticdungeongame.core.register.EDGBlockEntities;
import top.r3944realms.eroticdungeongame.core.register.EDGEntities;
import top.r3944realms.eroticdungeongame.core.register.EDGMenuTypes;
import top.r3944realms.eroticdungeongame.core.register.EDGParticleTypes;
import top.r3944realms.eroticdungeongame.util.EntityUtil;
import top.r3944realms.eroticdungeongame.util.WoodTypeHelper;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class ClientHandler {
    @net.minecraftforge.fml.common.Mod.EventBusSubscriber(modid = EroticDungeon.MOD_ID, bus = net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus.FORGE, value = Dist.CLIENT)
    public static class Game extends ClientHandler {

        @SubscribeEvent
        public static void onSpanishDonkeyTremble(RenderPlayerEvent event) {
            Player player = event.getEntity();
            if(player.isFullyFrozen()) return;
            if(player.isPassenger() && player.getVehicle() instanceof SeatEntity seat && seat.getLinkedBlockPos() != null) {
                BlockEntity blockEntity = player.level().getBlockEntity(seat.getLinkedBlockPos());
                if (blockEntity instanceof SpanishDonkeyBlockEntity spanishDonkeyBlock) {
                    if (spanishDonkeyBlock.isShock()) {
                        float time = player.tickCount * 0.5f;
                        float intensity = 0.3f + 0.2f * (float)Math.sin(time);

                        // 第三人称模型晃动
                        tremble(player, event.getPoseStack(), intensity);
                    }
                }
            }
        }

        /**
         * 处理视角变换事件 - 应用屏幕晃动
         */
        @SubscribeEvent
        public static void onCameraSetup(ViewportEvent.ComputeCameraAngles event) {
            Minecraft mc = Minecraft.getInstance();
            float shakeIntensity;
            if(mc.level != null && mc.player != null && mc.player.isPassenger() && mc.player.getVehicle() instanceof SeatEntity seat && seat.getLinkedBlockPos() != null) {
                BlockEntity blockEntity = mc.level.getBlockEntity(seat.getLinkedBlockPos());
                if (blockEntity instanceof SpanishDonkeyBlockEntity spanishDonkeyBlock) {
                    if (spanishDonkeyBlock.isShock()) {
                        float time = mc.player.tickCount * 0.5f;
                        shakeIntensity = 0.3f + 0.2f * (float)Math.sin(time);
                    } else return;
                } else return;
            } else return;
            if (shakeIntensity < 0.01f) {
                return;
            }

            float time = (float) (mc.player.tickCount + event.getPartialTick());

            // 简单的正弦波震动
            float shakeX = (float)Math.sin(time * 0.35) * shakeIntensity * 2.5f;
            float shakeY = (float)Math.cos(time * 0.3) * shakeIntensity * 2.0f;

            // 应用到相机角度
            event.setYaw(event.getYaw() + shakeX);
            event.setPitch(event.getPitch() + shakeY);

            // 轻微的屏幕偏移（更真实的震动感）
            if (shakeIntensity > 0.2f) {
                float offsetX = (float)Math.sin(time * 0.5) * shakeIntensity * 0.015f;
                float offsetY = (float)Math.cos(time * 0.45) * shakeIntensity * 0.01f;

                Camera camera = event.getCamera();
                Vec3 pos = camera.getPosition();
                camera.setPosition(
                        new Vec3(
                                pos.x + offsetX,
                                pos.y + offsetY,
                                pos.z
                        )
                );
            }
        }

        private static void tremble(Player player, PoseStack poseStack, float percent){
            float pRotationYaw = (float)(Math.cos((double)player.tickCount * 3.25) * Math.PI * percent);
            poseStack.mulPose(Axis.YP.rotationDegrees(pRotationYaw));
        }
        @SubscribeEvent
        public static void onKetBoardInput(InputEvent.Key event) {
            Minecraft minecraft = Minecraft.getInstance();
            LocalPlayer player = minecraft.player;
            if(player == null) return;
            if (EDGKeyBindings.KEY_QUIT.isDown()) {
                if (minecraft.level ==null) return;
                ItemStack itemInHand = player.getItemInHand(InteractionHand.MAIN_HAND);
                if (Services.WORK_SPACE.isInDevice(player)) {
                    EDGNetworkHandler.CHANNEL.sendToServer(new RequestQuitDevicePacket(itemInHand.isEmpty() || !itemInHand.getOrCreateTag().contains(DeviceKeyItem.LOCK_CODE) ? Optional.empty() : Optional.of(itemInHand.getOrCreateTag().getLong(DeviceKeyItem.LOCK_CODE)),Optional.empty()));
                } else {
                    List<HitResult> refLookAtEntityHitResult = EntityUtil.getRefLookAtEntityHitResult(player, minecraft.level, 6, Services.WORK_SPACE::isInDevice, i -> i.getBlock() instanceof ISeatBlock);
                    Entity entity = EntityUtil.getTheNearestEntityFromHitResultList(player, refLookAtEntityHitResult);
                    if (entity != null) {
                        EDGNetworkHandler.CHANNEL.sendToServer(new RequestQuitDevicePacket(itemInHand.isEmpty() || !itemInHand.getOrCreateTag().contains(DeviceKeyItem.LOCK_CODE) ? Optional.empty() : Optional.of(itemInHand.getOrCreateTag().getLong(DeviceKeyItem.LOCK_CODE)), Optional.of(entity.getUUID())));
                    }
                }
            }
        }
    }
    @net.minecraftforge.fml.common.Mod.EventBusSubscriber(modid = EroticDungeon.MOD_ID, bus = net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)
    public static class Mod extends ClientHandler {
        @SubscribeEvent
        public static void onFMLClientSetUp (FMLClientSetupEvent event) {
            event.enqueueWork(() -> {
                MenuScreens.register(EDGMenuTypes.DUNGEON_CRAFTING_MENU.get(), DungeonCraftingScreen::new);
                EDGArmPose.init();
            });
        }

        private static final Map<WoodType, SpanishDonkeyBlockRenderer> SPANISH_DONKEY_RENDERERS = new HashMap<>();
        private static final Map<String, LoveMachineBlockRenderer> LOVE_MACHINE_BLOCK_RENDERERS = new HashMap<>();
        @SubscribeEvent
        public static void onRegisterRenderer (EntityRenderersEvent.RegisterRenderers event) {
            event.registerBlockEntityRenderer(EDGBlockEntities.IRON_CAGE_SEAT_BLOCK_ENTITY.get(), context -> new IronCageBlockRenderer());
            for (WoodType woodType : WoodTypeHelper.SUPPORTED_WOOD_TYPES) {
                SpanishDonkeyBlockRenderer renderer = new SpanishDonkeyBlockRenderer(woodType);
                SPANISH_DONKEY_RENDERERS.put(woodType, renderer);
            }
            event.registerBlockEntityRenderer(
                    EDGBlockEntities.SPANISH_DONKEY_BLOCK_ENTITY.get(),
                    new BlockEntityRendererProvider<>() {
                        @Override
                        public @NotNull BlockEntityRenderer<SpanishDonkeyBlockEntity> create(@NotNull Context context) {
                            return new BlockEntityRenderer<>() {
                                private final Map<WoodType, SpanishDonkeyBlockRenderer> renderers = SPANISH_DONKEY_RENDERERS;

                                @Override
                                public void render(@NotNull SpanishDonkeyBlockEntity blockEntity, float partialTick, @NotNull PoseStack poseStack, @NotNull MultiBufferSource multiBufferSource, int packedLight, int packedOverlay) {
                                    BlockState state = blockEntity.getBlockState();
                                    // 从方块状态获取WoodType
                                    WoodType woodType;
                                    if (state.getBlock() instanceof SpanishDonkeyBlock spanishDonkeyBlock) {
                                        woodType = spanishDonkeyBlock.getWoodType();
                                    } else throw new RuntimeException("Unknown blockType: " + state.getBlock().getClass());
                                    SpanishDonkeyBlockRenderer renderer = renderers.get(woodType);
                                    if (renderer != null) {
                                        renderer.render(blockEntity, partialTick, poseStack, multiBufferSource, packedLight, packedOverlay);
                                    }
                                }
                            };

                        }
                    }
            );
            for (String type : new String[]{"end_rod", "lightning_rod"}) {
                LOVE_MACHINE_BLOCK_RENDERERS.put(type, new LoveMachineBlockRenderer(type));
            }
            event.registerBlockEntityRenderer(EDGBlockEntities.LOVE_MACHINE_BLOCK_ENTITY.get(), new BlockEntityRendererProvider<>() {
                @Override
                public @NotNull BlockEntityRenderer<LoveMachineBlockEntity> create(@NotNull Context context) {
                    return new BlockEntityRenderer<>() {
                        private final Map<String, LoveMachineBlockRenderer> renderers = LOVE_MACHINE_BLOCK_RENDERERS;

                        @Override
                        public void render(@NotNull LoveMachineBlockEntity loveMachineBlockEntity, float v, @NotNull PoseStack poseStack, @NotNull MultiBufferSource multiBufferSource, int i, int i1) {
                            if (loveMachineBlockEntity.getBlockState().getBlock() instanceof LoveMachineBlock machine) {
                                LOVE_MACHINE_BLOCK_RENDERERS.get(machine.type).render(loveMachineBlockEntity, v, poseStack, multiBufferSource, i, i1);
                            }
                        }
                    };
                }
            });
            event.registerEntityRenderer(EDGEntities.SEAT.get(), EmptySeatRenderer::new);
        }
        @SubscribeEvent
        public static void onRegisterParticles (RegisterParticleProvidersEvent event) {
            event.registerSpriteSet(
                    EDGParticleTypes.VERTICAL_WHIP_SWEEP.get(),
                    VerticalWhipSweepParticle.Provider::new
            );
            event.registerSpriteSet(
                    EDGParticleTypes.WHIP_SCAR.get(),
                    WhipScarParticle.Provider::new
            );
        }
    }
    @SubscribeEvent
    public static void onRegisterKeyMappings (RegisterKeyMappingsEvent event) {
        event.register(EDGKeyBindings.KEY_QUIT);
    }


}
