package hu.jgj52.megeszlekmoro.client;

import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Hand;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.screen.slot.SlotActionType;

import java.util.Random;

public class MegeszlekmoroClient implements ClientModInitializer {
    private final MinecraftClient mc = MinecraftClient.getInstance();
    private final Random random = new Random();
    private static final float INTERACTION_DISTANCE = 4.0f;

    // Cooldown timers
    private long lastActionTime = 0;
    private long nextActionDelay = 0;
    private boolean isEating = false;
    private int eatingTicks = 0;
    private boolean rightClickPressed = false;
    private boolean isThrowingXP = false;
    private int spawn = 0;

    // Command timers
    private long lastCommandTime = 0;
    private static final long COMMAND_INTERVAL = 60000; // 1 minute in milliseconds
    private boolean waitingForLoadkit = false;

    // Death handling
    private boolean wasAlive = true;
    private int loadkitDelayTicks = 0;
    private boolean waitingForLoadkitDelay = false;

    @Override
    public void onInitializeClient() {
        System.out.println("[GoldenAppleBot] Mod loaded!");
        ClientTickEvents.END_CLIENT_TICK.register(client -> onTick());

        // Register chat message listener
        net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents.GAME.register((message, overlay) -> {
            if (mc.player == null) return;

            String messageText = message.getString();
            String playerName = mc.player.getName().getString();

            if (messageText.contains(playerName)) {
                System.out.println("[GoldenAppleBot] Detected own name '" + playerName + "' in chat, will /loadkit in 10 ticks");
                waitingForLoadkitDelay = true;
                loadkitDelayTicks = 0;
            }
        });
    }

    private void onTick() {
        if (mc.world == null || mc.player == null) return;

        // Check for death and send message
        if (wasAlive && !mc.player.isAlive()) {
            String playerName = mc.player.getName().getString();
            sendChatMessage(playerName);
            System.out.println("[GoldenAppleBot] Player died, sent '" + playerName + "' in chat");
        }
        wasAlive = mc.player.isAlive();

        // Handle loadkit delay after detecting own name in chat
        if (waitingForLoadkitDelay) {
            loadkitDelayTicks++;
            if (loadkitDelayTicks >= 10) {
                sendCommand("/loadkit");
                System.out.println("[GoldenAppleBot] Sent /loadkit after 10 tick delay");
                waitingForLoadkitDelay = false;
                loadkitDelayTicks = 0;
            }
        }

        if (spawn == 600) {
            //sendCommand("/ffa");
            //sendCommand("/spawn");
            //sendCommand("/loadkit");
            spawn = 0;
        } else {
            spawn++;
        }

        // Handle eating state
        if (isEating) {
            eatingTicks++;
            if (eatingTicks >= 32) { // Golden apples take 32 ticks (1.6 seconds) to eat
                stopEating();
            }
            return;
        }

        // Always check for eating/dropping regardless of target presence
        performAction();

        PlayerEntity target = getTargetPlayer();
        if (target == null) {
            stopMoving();
            return;
        }

        // Only rotate towards target if NOT throwing XP
        if (!isThrowingXP) {
            // Calculate target rotation only for movement purposes
            Vec3d targetPos = target.getPos().add(0, target.getStandingEyeHeight(), 0);
            Vec3d playerPos = mc.player.getPos().add(0, mc.player.getStandingEyeHeight(), 0);

            double dx = targetPos.x - playerPos.x;
            double dy = targetPos.y - playerPos.y;
            double dz = targetPos.z - playerPos.z;
            double distXZ = Math.sqrt(dx * dx + dz * dz);

            float targetYaw = (float) (MathHelper.atan2(dz, dx) * 180.0 / Math.PI) - 90f;
            float targetPitch = (float) -(MathHelper.atan2(dy, distXZ) * 180.0 / Math.PI);

            // Only rotate if not eating and need to move towards target
            double distance = mc.player.getPos().distanceTo(target.getPos());

            if (distance > 3.5) {
                // Smooth human-like rotation only when moving
                mc.player.setYaw(smoothHumanRotation(mc.player.getYaw(), targetYaw));
                mc.player.setPitch(smoothHumanRotation(mc.player.getPitch(), targetPitch));

                mc.options.forwardKey.setPressed(true);
                if (mc.player.isOnGround() && random.nextDouble() < 0.015) {
                    mc.player.jump();
                }
            } else {
                stopMoving();
            }
        } else {
            // If throwing XP, keep looking down but still move towards target if needed
            mc.player.setPitch(90f);

            double distance = mc.player.getPos().distanceTo(target.getPos());
            if (distance > 3.5) {
                Vec3d targetPos = target.getPos();
                Vec3d playerPos = mc.player.getPos();
                double dx = targetPos.x - playerPos.x;
                double dz = targetPos.z - playerPos.z;
                float targetYaw = (float) (MathHelper.atan2(dz, dx) * 180.0 / Math.PI) - 90f;
                mc.player.setYaw(smoothHumanRotation(mc.player.getYaw(), targetYaw));

                mc.options.forwardKey.setPressed(true);
                if (mc.player.isOnGround() && random.nextDouble() < 0.015) {
                    mc.player.jump();
                }
            } else {
                stopMoving();
            }
        }
    }

    private PlayerEntity getTargetPlayer() {
        if (mc.player == null || mc.world == null) return null;

        PlayerEntity nearestPlayer = null;
        double nearestDistance = Double.MAX_VALUE;

        for (PlayerEntity player : mc.world.getPlayers()) {
            // Skip self, dead players, and players with Y > 130
            if (player == mc.player || !player.isAlive() || player.getY() > 130) continue;

            double distance = mc.player.getPos().distanceTo(player.getPos());
            if (distance < nearestDistance) {
                nearestDistance = distance;
                nearestPlayer = player;
            }
        }

        return nearestPlayer;
    }

    private boolean isArmorDamaged() {
        // Check all armor slots (helmet, chestplate, leggings, boots)
        for (ItemStack armorPiece : mc.player.getInventory().armor) {
            if (!armorPiece.isEmpty() && armorPiece.isDamaged()) {
                return true;
            }
        }
        return false;
    }

    private void performAction() {
        // Check health status every tick for instant response
        if (mc.player.getHealth() >= mc.player.getMaxHealth() && isArmorDamaged()) {
            // Switch to XP bottles and throw downward when at full health AND armor is damaged
            switchToXPBottle();

            if (!isThrowingXP) {
                startThrowingXP();
            }
        } else {
            // Stop throwing XP and eat golden apple when not at full health or armor is not damaged
            if (isThrowingXP) {
                stopThrowingXP();
            }
            if (!isEating && mc.player.getHealth() < mc.player.getMaxHealth()) {
                eatGoldenApple();
            }
        }
    }

    private void eatGoldenApple() {
        // Find golden apple in hotbar first
        int slot = findItemInHotbar(Items.GOLDEN_APPLE);
        if (slot == -1) {
            slot = findItemInHotbar(Items.ENCHANTED_GOLDEN_APPLE);
        }

        // If not in hotbar, try to move from inventory
        if (slot == -1) {
            if (moveItemToHotbar(Items.GOLDEN_APPLE) || moveItemToHotbar(Items.ENCHANTED_GOLDEN_APPLE)) {
                slot = findItemInHotbar(Items.GOLDEN_APPLE);
                if (slot == -1) {
                    slot = findItemInHotbar(Items.ENCHANTED_GOLDEN_APPLE);
                }
            }
        }

        if (slot != -1) {
            // Switch to the golden apple slot
            mc.player.getInventory().selectedSlot = slot;

            // Start eating by pressing right click
            startEating();

            System.out.println("[GoldenAppleBot] Started eating golden apple!");
        } else {
            System.out.println("[GoldenAppleBot] No golden apple found!");
        }
    }

    private void dropExperienceBottle() {
        // Find experience bottle in hotbar first
        int slot = findItemInHotbar(Items.EXPERIENCE_BOTTLE);

        // If not in hotbar, try to move from inventory
        if (slot == -1) {
            if (moveItemToHotbar(Items.EXPERIENCE_BOTTLE)) {
                slot = findItemInHotbar(Items.EXPERIENCE_BOTTLE);
            }
        }

        if (slot != -1) {
            // Switch to the experience bottle slot
            mc.player.getInventory().selectedSlot = slot;

            // Drop one experience bottle
            mc.player.dropSelectedItem(false);

            System.out.println("[GoldenAppleBot] Dropped experience bottle!");
        } else {
            System.out.println("[GoldenAppleBot] No experience bottle found!");
        }
    }

    private void startThrowingXP() {
        // Find experience bottle in hotbar first
        int slot = findItemInHotbar(Items.EXPERIENCE_BOTTLE);

        // If not in hotbar, try to move from inventory
        if (slot == -1) {
            if (moveItemToHotbar(Items.EXPERIENCE_BOTTLE)) {
                slot = findItemInHotbar(Items.EXPERIENCE_BOTTLE);
            }
        }

        if (slot != -1) {
            // Switch to the experience bottle slot
            mc.player.getInventory().selectedSlot = slot;

            // Look straight down (90 degrees)
            mc.player.setPitch(90f);

            // Start holding right click to continuously throw XP bottles downward
            isThrowingXP = true;
            mc.options.useKey.setPressed(true);

            System.out.println("[GoldenAppleBot] Started throwing XP bottles downward!");
        } else {
            System.out.println("[GoldenAppleBot] No experience bottle found!");
        }
    }

    private void stopThrowingXP() {
        if (isThrowingXP) {
            isThrowingXP = false;
            mc.options.useKey.setPressed(false);
            System.out.println("[GoldenAppleBot] Stopped throwing XP bottles!");
        }
    }

    private void switchToXPBottle() {
        // Find experience bottle in hotbar first
        int slot = findItemInHotbar(Items.EXPERIENCE_BOTTLE);

        // If not in hotbar, try to move from inventory
        if (slot == -1) {
            if (moveItemToHotbar(Items.EXPERIENCE_BOTTLE)) {
                slot = findItemInHotbar(Items.EXPERIENCE_BOTTLE);
            }
        }

        if (slot != -1) {
            // Switch to the experience bottle slot
            mc.player.getInventory().selectedSlot = slot;
        }
    }

    private boolean isNearAndLookingAtTarget(PlayerEntity target) {
        if (target == null) return false;

        // Check distance (within 4 blocks)
        double distance = mc.player.getPos().distanceTo(target.getPos());
        if (distance > INTERACTION_DISTANCE) return false;

        // Check if looking at target (within reasonable angle)
        Vec3d playerPos = mc.player.getPos().add(0, mc.player.getStandingEyeHeight(), 0);
        Vec3d targetPos = target.getPos().add(0, target.getStandingEyeHeight(), 0);

        Vec3d directionToTarget = targetPos.subtract(playerPos).normalize();
        Vec3d playerLookDirection = mc.player.getRotationVec(1.0f);

        // Calculate dot product to check if looking in target's direction
        double dotProduct = playerLookDirection.dotProduct(directionToTarget);

        // Consider "looking at" if within ~45 degree cone (dot product > 0.7)
        return dotProduct > 0.7;
    }

    private void handleCommands() {
        long currentTime = System.currentTimeMillis();

        // Check if it's time to run commands (every minute)
        if (currentTime - lastCommandTime >= COMMAND_INTERVAL) {
            if (!waitingForLoadkit) {
                // Send /spawn command first
                sendCommand("/spawn");
                waitingForLoadkit = true;
                lastCommandTime = currentTime;
                System.out.println("[GoldenAppleBot] Sent /spawn command");
            }
        }

        // Send /loadkit command 2 seconds after /spawn
        if (waitingForLoadkit && (currentTime - lastCommandTime >= 2000)) {
            sendCommand("/loadkit");
            waitingForLoadkit = false;
            System.out.println("[GoldenAppleBot] Sent /loadkit command");
        }
    }

    private void sendCommand(String command) {
        if (mc.player != null) {
            mc.player.networkHandler.sendChatCommand(command.substring(1)); // Remove the '/' prefix
        }
    }

    private void sendChatMessage(String message) {
        if (mc.player != null) {
            mc.player.networkHandler.sendChatMessage(message);
        }
    }

    private void startEating() {
        isEating = true;
        eatingTicks = 0;
        rightClickPressed = true;
        mc.options.useKey.setPressed(true);

        // Also trigger the interaction directly
        if (mc.interactionManager != null) {
            mc.interactionManager.interactItem(mc.player, Hand.MAIN_HAND);
        }
    }

    private void stopEating() {
        isEating = false;
        eatingTicks = 0;
        if (rightClickPressed) {
            mc.options.useKey.setPressed(false);
            rightClickPressed = false;
        }
    }

    private int findItemInHotbar(net.minecraft.item.Item item) {
        for (int i = 0; i < 9; i++) {
            ItemStack stack = mc.player.getInventory().getStack(i);
            if (stack.getItem() == item && !stack.isEmpty()) {
                return i;
            }
        }
        return -1;
    }

    private boolean moveItemToHotbar(net.minecraft.item.Item item) {
        // Find item in main inventory (slots 9-35)
        int sourceSlot = -1;
        for (int i = 9; i < 36; i++) {
            ItemStack stack = mc.player.getInventory().getStack(i);
            if (stack.getItem() == item && !stack.isEmpty()) {
                sourceSlot = i;
                break;
            }
        }

        if (sourceSlot == -1) return false;

        // Find empty hotbar slot
        int targetSlot = -1;
        for (int i = 0; i < 9; i++) {
            if (mc.player.getInventory().getStack(i).isEmpty()) {
                targetSlot = i;
                break;
            }
        }

        if (targetSlot == -1) {
            // No empty slot, use current selected slot
            targetSlot = mc.player.getInventory().selectedSlot;
        }

        // Move item using interaction manager
        if (mc.interactionManager != null && mc.player.currentScreenHandler != null) {
            try {
                // Click source slot
                mc.interactionManager.clickSlot(
                        mc.player.currentScreenHandler.syncId,
                        sourceSlot,
                        0,
                        SlotActionType.PICKUP,
                        mc.player
                );

                // Click target slot
                mc.interactionManager.clickSlot(
                        mc.player.currentScreenHandler.syncId,
                        targetSlot,
                        0,
                        SlotActionType.PICKUP,
                        mc.player
                );

                return true;
            } catch (Exception e) {
                System.out.println("[GoldenAppleBot] Error moving item: " + e.getMessage());
                return false;
            }
        }
        return false;
    }

    private float smoothHumanRotation(float current, float target) {
        float delta = MathHelper.wrapDegrees(target - current);

        float maxChange = 0.5f + random.nextFloat() * 1.5f; // 0.5°–2° per tick
        if (delta > maxChange) delta = maxChange;
        if (delta < -maxChange) delta = -maxChange;

        float jitter = (float) ((random.nextDouble() - 0.5) * 0.2); // tiny human jitter
        return current + delta + jitter;
    }

    private void stopMoving() {
        mc.options.forwardKey.setPressed(false);
        mc.options.leftKey.setPressed(false);
        mc.options.rightKey.setPressed(false);
        mc.options.backKey.setPressed(false);
    }
}