package com.tiedup.remake.events.system;

import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.core.SystemMessageManager;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.dialogue.GagTalkManager;
import com.tiedup.remake.state.IBondageState;
import com.tiedup.remake.util.GagMaterial;
import com.tiedup.remake.v2.bondage.component.ComponentType;
import com.tiedup.remake.v2.bondage.component.GaggingComponent;
import com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem;
import com.tiedup.remake.util.KidnappedHelper;
import com.tiedup.remake.util.TiedUpUtils;
import com.tiedup.remake.v2.BodyRegionV2;
import com.tiedup.remake.v2.bondage.capability.V2EquipmentHelper;
import java.util.List;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.event.CommandEvent;
import net.minecraftforge.event.ServerChatEvent;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;

/**
 * ChatEventHandler - Intercepts chat messages to apply gag effects.
 * Evolution: Implements proximity-based chat for gagged players.
 *
 *
 * Security fix: Now blocks communication commands (/msg, /tell, etc.) when gagged
 * to prevent gag bypass exploit
 */
@Mod.EventBusSubscriber(modid = TiedUpMod.MOD_ID)
public class ChatEventHandler {

    /** List of communication commands that should be blocked when gagged */
    private static final String[] BLOCKED_COMMANDS = {
        "msg",
        "tell",
        "w",
        "whisper",
        "r",
        "reply",
        "me",
    };

    @SubscribeEvent
    public static void onPlayerChat(ServerChatEvent event) {
        ServerPlayer player = event.getPlayer();
        IBondageState state = KidnappedHelper.getKidnappedState(player);

        if (state != null && state.isGagged()) {
            ItemStack gagStack = V2EquipmentHelper.getInRegion(
                player,
                BodyRegionV2.MOUTH
            );

            // V2: check gagging component
            GaggingComponent gaggingComp = DataDrivenBondageItem.getComponent(
                gagStack, ComponentType.GAGGING, GaggingComponent.class);
            boolean isGagItem = gaggingComp != null;

            if (!gagStack.isEmpty() && isGagItem) {
                String originalMessage = event.getRawText();
                // V2: get material from GaggingComponent
                GagMaterial material = null;
                if (gaggingComp != null) {
                    material = gaggingComp.getMaterial();
                }
                // material stays null if no component; GagTalkManager handles null → CLOTH fallback

                // 1. Process the message through our GagTalkManager V2
                Component muffledMessage = GagTalkManager.processGagMessage(
                    state,
                    gagStack,
                    originalMessage
                );

                // 2. Proximity Chat Logic
                boolean useProximity =
                    SettingsAccessor.isGagTalkProximityEnabled(
                        player.level().getGameRules()
                    );

                if (useProximity) {
                    // Cancel global and send to nearby
                    event.setCanceled(true);

                    Component finalChat = Component.literal("<")
                        .append(player.getDisplayName())
                        .append("> ")
                        .append(muffledMessage);

                    double range = material != null
                        ? material.getTalkRange()
                        : (gaggingComp != null ? gaggingComp.getRange() : 10.0);

                    List<ServerPlayer> nearbyPlayers =
                        TiedUpUtils.getPlayersAround(
                            player.level(),
                            player.blockPosition(),
                            range
                        );

                    int listeners = 0;
                    for (ServerPlayer other : nearbyPlayers) {
                        // Check if receiver has earplugs (they can't hear)
                        IBondageState receiverState =
                            KidnappedHelper.getKidnappedState(other);
                        if (
                            receiverState != null && receiverState.hasEarplugs()
                        ) {
                            // Can't hear - skip this player
                            continue;
                        }

                        other.sendSystemMessage(finalChat);
                        if (other != player) listeners++;
                    }

                    if (listeners == 0) {
                        player.displayClientMessage(
                            Component.translatable(
                                "chat.tiedup.gag.no_one_heard"
                            ).withStyle(
                                net.minecraft.ChatFormatting.ITALIC,
                                net.minecraft.ChatFormatting.GRAY
                            ),
                            true
                        );
                    }
                } else {
                    // Just replace message but keep it global
                    event.setMessage(muffledMessage);
                }

                TiedUpMod.LOGGER.debug(
                    "[Chat] {} muffled message processed (Proximity: {})",
                    player.getName().getString(),
                    useProximity
                );
            }
        }
    }

    /**
     * Intercept commands to prevent gagged players from using communication commands.
     * Blocks /msg, /tell, /w, /whisper, /r, /reply, /me when player is gagged.
     *
     * Security fix: Prevents gag bypass exploit via private messages
     */
    @SubscribeEvent(priority = EventPriority.HIGHEST)
    public static void onCommand(CommandEvent event) {
        // Only check if sender is a ServerPlayer
        if (
            !(event
                        .getParseResults()
                        .getContext()
                        .getSource()
                        .getEntity() instanceof
                    ServerPlayer player)
        ) {
            return;
        }

        // Check if player is gagged
        IBondageState state = KidnappedHelper.getKidnappedState(player);
        if (state == null || !state.isGagged()) {
            return; // Not gagged, allow all commands
        }

        // Get the command name (first part of the command string)
        String commandInput = event.getParseResults().getReader().getString();
        if (commandInput.isEmpty()) {
            return;
        }

        // Remove leading slash if present
        String commandName = commandInput.startsWith("/")
            ? commandInput.substring(1)
            : commandInput;
        // Get only the first word (command name)
        commandName = commandName.split(" ")[0].toLowerCase();

        // Check if this is a blocked communication command
        for (String blockedCmd : BLOCKED_COMMANDS) {
            if (commandName.equals(blockedCmd)) {
                // Block the command
                event.setCanceled(true);

                // Send muffled message to player
                SystemMessageManager.sendToPlayer(
                    player,
                    SystemMessageManager.MessageCategory.ERROR,
                    "Mmmph! You can't use that command while gagged!"
                );

                TiedUpMod.LOGGER.debug(
                    "[Chat] Blocked command '{}' from gagged player {}",
                    commandName,
                    player.getName().getString()
                );

                return;
            }
        }
    }
}
