package com.tiedup.remake.items;

import com.tiedup.remake.core.ModSounds;
import com.tiedup.remake.core.SystemMessageManager;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.items.base.ItemOwnerTarget;
import com.tiedup.remake.v2.bondage.CollarHelper;
import com.tiedup.remake.state.IRestrainable;
import com.tiedup.remake.util.KidnappedHelper;
import com.tiedup.remake.v2.BodyRegionV2;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import net.minecraft.ChatFormatting;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.Nullable;

public class ItemShockerController extends ItemOwnerTarget {

    private static final String NBT_BROADCAST = "broadcast";
    private static final String NBT_RADIUS = "radius";

    public ItemShockerController() {
        super(new net.minecraft.world.item.Item.Properties().stacksTo(1));
    }

    @Override
    public void appendHoverText(
        ItemStack stack,
        @Nullable Level level,
        List<Component> tooltip,
        TooltipFlag flag
    ) {
        super.appendHoverText(stack, level, tooltip, flag);

        appendOwnerTooltip(stack, tooltip, "Right-click a player");

        if (isBroadcastEnabled(stack)) {
            tooltip.add(
                Component.translatable("item.tiedup.shocker.mode_broadcast")
                    .withStyle(ChatFormatting.DARK_RED)
            );
            tooltip.add(
                Component.translatable("item.tiedup.shocker.broadcast_desc")
                    .withStyle(ChatFormatting.GRAY)
                    .withStyle(ChatFormatting.ITALIC)
            );
        } else {
            tooltip.add(
                Component.translatable("item.tiedup.shocker.mode_targeted")
                    .withStyle(ChatFormatting.BLUE)
            );
            if (hasTarget(stack)) {
                String displayName = getTargetName(stack);
                boolean isDisconnected = true;

                if (level != null) {
                    Player target = level.getPlayerByUUID(getTargetId(stack));
                    if (target != null) {
                        IRestrainable targetState =
                            KidnappedHelper.getKidnappedState(target);
                        if (targetState != null && targetState.hasCollar()) {
                            isDisconnected = false;
                            ItemStack collar = targetState.getEquipment(
                                BodyRegionV2.NECK
                            );
                            if (
                                CollarHelper.isCollar(collar) &&
                                CollarHelper.hasNickname(collar)
                            ) {
                                displayName =
                                    CollarHelper.getNickname(collar) +
                                    " (" +
                                    displayName +
                                    ")";
                            }
                        }
                    }
                }

                MutableComponent targetComp = Component.literal("  > ")
                    .withStyle(ChatFormatting.BLUE)
                    .append(
                        Component.literal(displayName).withStyle(
                            isDisconnected
                                ? ChatFormatting.STRIKETHROUGH
                                : ChatFormatting.WHITE
                        )
                    );

                if (isDisconnected) {
                    targetComp.append(
                        Component.translatable("item.tiedup.shocker.freed")
                            .withStyle(ChatFormatting.RED)
                            .withStyle(ChatFormatting.BOLD)
                    );
                }
                tooltip.add(targetComp);
            } else {
                tooltip.add(
                    Component.translatable("item.tiedup.shocker.no_target")
                        .withStyle(ChatFormatting.GRAY)
                );
            }
        }

        tooltip.add(
            Component.translatable("item.tiedup.shocker.radius", getRadius(stack))
                .withStyle(ChatFormatting.GREEN)
        );
        tooltip.add(
            Component.translatable("item.tiedup.shocker.hint")
                .withStyle(ChatFormatting.DARK_GRAY)
                .withStyle(ChatFormatting.ITALIC)
        );
    }

    @Override
    public InteractionResultHolder<ItemStack> use(
        Level level,
        Player player,
        InteractionHand hand
    ) {
        ItemStack stack = player.getItemInHand(hand);

        if (player.isShiftKeyDown()) {
            if (!level.isClientSide) {
                if (hasOwner(stack) && !isOwner(stack, player)) {
                    SystemMessageManager.sendToPlayer(
                        player,
                        SystemMessageManager.MessageCategory.SHOCKER_NOT_OWNER
                    );
                    return InteractionResultHolder.fail(stack);
                }

                boolean newState = !isBroadcastEnabled(stack);
                setBroadcastEnabled(stack, newState);
                player.setItemInHand(hand, stack);
                SystemMessageManager.sendToPlayer(
                    player,
                    SystemMessageManager.MessageCategory.SHOCKER_MODE_SET,
                    (newState ? "BROADCAST" : "TARGETED")
                );
            }
            return InteractionResultHolder.sidedSuccess(
                stack,
                level.isClientSide()
            );
        }

        if (level.isClientSide) return InteractionResultHolder.success(stack);

        IRestrainable playerState = KidnappedHelper.getKidnappedState(player);
        if (
            playerState != null && playerState.isTiedUp()
        ) return InteractionResultHolder.fail(stack);

        if (!hasOwner(stack)) {
            SystemMessageManager.sendToPlayer(
                player,
                SystemMessageManager.MessageCategory.ERROR,
                "You must claim this shocker first! (Right-click a player)"
            );
            return InteractionResultHolder.fail(stack);
        }

        if (!isOwner(stack, player)) {
            SystemMessageManager.sendToPlayer(
                player,
                SystemMessageManager.MessageCategory.SHOCKER_NOT_OWNER
            );
            return InteractionResultHolder.fail(stack);
        }

        List<LivingEntity> nearbyTargets = getNearbyKidnappedTargets(
            level,
            player,
            stack
        );

        if (isBroadcastEnabled(stack)) {
            for (LivingEntity target : nearbyTargets) {
                IRestrainable targetState = KidnappedHelper.getKidnappedState(
                    target
                );
                if (targetState != null) targetState.shockKidnapped();
            }

            if (nearbyTargets.isEmpty()) {
                SystemMessageManager.sendToPlayer(
                    player,
                    SystemMessageManager.MessageCategory.ERROR,
                    "No valid targets in range!"
                );
            } else {
                SystemMessageManager.sendToPlayer(
                    player,
                    SystemMessageManager.MessageCategory.INFO,
                    "Broadcast shock triggered! (" +
                        nearbyTargets.size() +
                        " targets)"
                );
                playTriggerSound(player);
            }
        } else if (hasTarget(stack)) {
            Player target = level.getPlayerByUUID(getTargetId(stack));
            IRestrainable targetState =
                target != null
                    ? KidnappedHelper.getKidnappedState(target)
                    : null;

            if (
                target != null &&
                targetState != null &&
                targetState.hasCollar() &&
                nearbyTargets.contains(target)
            ) {
                targetState.shockKidnapped();
                String name = target.getName().getString();
                SystemMessageManager.sendToPlayer(
                    player,
                    SystemMessageManager.MessageCategory.SHOCKER_TRIGGERED,
                    name
                );
                playTriggerSound(player);
            } else {
                String error = (target == null)
                    ? "Target is out of range or in another dimension!"
                    : (!targetState.hasCollar()
                          ? "Target is no longer wearing a collar!"
                          : "Target is out of range!");
                SystemMessageManager.sendToPlayer(
                    player,
                    SystemMessageManager.MessageCategory.ERROR,
                    error
                );
            }
        } else {
            SystemMessageManager.sendToPlayer(
                player,
                SystemMessageManager.MessageCategory.ERROR,
                "No target set and broadcast is disabled!"
            );
        }

        return InteractionResultHolder.success(stack);
    }

    /**
     */
    @Override
    public InteractionResult interactLivingEntity(
        ItemStack stack,
        Player player,
        LivingEntity target,
        InteractionHand hand
    ) {
        if (player.level().isClientSide) return InteractionResult.SUCCESS;

        IRestrainable playerState = KidnappedHelper.getKidnappedState(player);
        if (
            playerState != null && playerState.isTiedUp()
        ) return InteractionResult.FAIL;

        // Claim shocker if unclaimed
        if (!hasOwner(stack)) {
            setOwner(stack, player);
            SystemMessageManager.sendToPlayer(
                player,
                SystemMessageManager.MessageCategory.SHOCKER_CLAIMED
            );
        } else if (!isOwner(stack, player)) {
            SystemMessageManager.sendToPlayer(
                player,
                SystemMessageManager.MessageCategory.SHOCKER_NOT_OWNER
            );
            return InteractionResult.FAIL;
        }

        // Connect to target (works with any LivingEntity that can be kidnapped)
        IRestrainable targetState = KidnappedHelper.getKidnappedState(target);
        if (targetState != null) {
            setTarget(stack, target);
            player.setItemInHand(hand, stack);
            SystemMessageManager.sendChatToPlayer(
                player,
                "Connected to " + target.getName().getString(),
                ChatFormatting.GREEN
            );
            return InteractionResult.SUCCESS;
        }

        return InteractionResult.PASS;
    }

    /**
     * Returns all kidnappable entities in range wearing shock collars owned by the shocker owner or in public mode.
     */
    private List<LivingEntity> getNearbyKidnappedTargets(
        Level level,
        Player source,
        ItemStack stack
    ) {
        double radius = getRadius(stack);
        UUID ownerId = getOwnerId(stack);
        List<LivingEntity> targets = new ArrayList<>();

        // Check all living entities in range
        for (LivingEntity entity : level.getEntitiesOfClass(
            LivingEntity.class,
            source.getBoundingBox().inflate(radius)
        )) {
            if (entity == source) continue;

            IRestrainable state = KidnappedHelper.getKidnappedState(entity);
            if (state != null && state.hasCollar()) {
                ItemStack collarStack = state.getEquipment(BodyRegionV2.NECK);
                if (CollarHelper.canShock(collarStack)) {
                    if (
                        CollarHelper.isOwner(collarStack, ownerId) ||
                        CollarHelper.isPublicShock(collarStack)
                    ) {
                        targets.add(entity);
                    }
                }
            }
        }
        return targets;
    }

    private void playTriggerSound(Player player) {
        player
            .level()
            .playSound(
                null,
                player.blockPosition(),
                ModSounds.SHOCKER_ACTIVATED.get(),
                net.minecraft.sounds.SoundSource.PLAYERS,
                0.5f,
                1.0f
            );
    }

    public boolean isBroadcastEnabled(ItemStack stack) {
        CompoundTag tag = stack.getTag();
        return tag != null && tag.getBoolean(NBT_BROADCAST);
    }

    public void setBroadcastEnabled(ItemStack stack, boolean enabled) {
        stack.getOrCreateTag().putBoolean(NBT_BROADCAST, enabled);
    }

    public int getRadius(ItemStack stack) {
        CompoundTag tag = stack.getTag();
        return (tag != null && tag.contains(NBT_RADIUS))
            ? tag.getInt(NBT_RADIUS)
            : com.tiedup.remake.core.SettingsAccessor.getShockerControllerRadius(
                  null
              );
    }

    public void setRadius(ItemStack stack, int radius) {
        stack.getOrCreateTag().putInt(NBT_RADIUS, radius);
    }

    public static ItemStack mergeShockers(List<ItemStack> stacks) {
        if (stacks == null || stacks.size() <= 1) return ItemStack.EMPTY;

        int totalRadius = 0;
        for (ItemStack s : stacks) {
            if (s.getItem() instanceof ItemShockerController sc) {
                totalRadius += sc.getRadius(s);
            }
        }

        ItemStack result = new ItemStack(stacks.get(0).getItem());
        ((ItemShockerController) result.getItem()).setRadius(
            result,
            totalRadius
        );
        return result;
    }
}
