package com.tiedup.remake.core;

import java.util.List;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;

/**
 * System message manager for TiedUp! mod.
 *
 * Handles action bar messages (displayed on screen above hotbar)
 * as opposed to chat messages.
 *
 * Use cases:
 * - Action feedback: "X is tying you up!"
 * - System info: "You can't do that while tied"
 * - Progress: "Resistance: 50"
 * - State changes: "You have been enslaved"
 *
 * This is different from EntityDialogueManager which handles
 * chat messages (what entities SAY to players).
 */
public class SystemMessageManager {

    // MESSAGE CATEGORIES

    /**
     * Categories for system messages.
     */
    public enum MessageCategory {
        // === RESTRAINT ACTIONS (done TO you) ===
        BEING_TIED, // "X is tying you up!"
        TIED_UP, // "X tied you up, you can't move!"
        BEING_GAGGED, // "X is gagging you!"
        GAGGED, // "X gagged you, you can't speak!"
        BEING_BLINDFOLDED, // "X is blindfolding you!"
        BLINDFOLDED, // "X blindfolded you, you can't see!"
        BEING_COLLARED, // "X is putting a collar on you!"
        COLLARED, // "X collared you!"
        EARPLUGS_ON, // "X put earplugs on you!"
        MITTENS_ON, // "X put mittens on you!"
        ENSLAVED, // "You have been enslaved by X!"

        // === RESTRAINT ACTIONS (done BY you - kidnapper's perspective) ===
        TYING_TARGET, // "You are tying X..."
        TIED_TARGET, // "You tied X!"
        GAGGING_TARGET, // "You are gagging X..."
        GAGGED_TARGET, // "You gagged X!"
        BLINDFOLDING_TARGET, // "You are blindfolding X..."
        BLINDFOLDED_TARGET, // "You blindfolded X!"
        COLLARING_TARGET, // "You are collaring X..."
        COLLARED_TARGET, // "You collared X!"

        // === RELEASE ACTIONS ===
        UNTIED, // "X untied you!"
        UNGAGGED, // "X removed your gag!"
        UNBLINDFOLDED, // "X removed your blindfold!"
        UNCOLLARED, // "X removed your collar!"
        FREED, // "You have been freed!"

        // === STRUGGLE SYSTEM ===
        STRUGGLE_SUCCESS, // "You loosened the binds!"
        STRUGGLE_FAIL, // "You couldn't loosen the binds..."
        STRUGGLE_BROKE_FREE, // "You broke free!"
        STRUGGLE_SHOCKED, // "You were shocked for struggling!"
        STRUGGLE_COLLAR_SUCCESS, // "You manage to damage the lock!"
        STRUGGLE_COLLAR_FAIL, // "You try to reach the lock, but can't get a good grip."

        // === RESTRICTIONS (TIED) ===
        CANT_MOVE, // "You can't move while tied!"
        CANT_ATTACK_TIED, // "You can't attack while tied!"
        CANT_USE_ITEM_TIED, // "You can't use items while tied!"
        CANT_OPEN_INVENTORY, // "You can't open inventory while tied!"
        CANT_INTERACT_TIED, // "You can't interact while tied!"
        CANT_SPEAK, // "You can't speak while gagged!"
        CANT_SEE, // "You can't see while blindfolded!"
        CANT_BREAK_TIED, // "You can't break blocks while tied!"
        CANT_PLACE_TIED, // "You can't place blocks while tied!"
        NO_ELYTRA, // "You can't fly with elytra while tied!"

        // === RESTRICTIONS (MITTENS) ===
        CANT_ATTACK_MITTENS, // "You can't attack with mittens on!"
        CANT_USE_ITEM_MITTENS, // "You can't use items with mittens on!"
        CANT_INTERACT_MITTENS, // "You can't interact with mittens on!"
        CANT_BREAK_MITTENS, // "You can't break blocks with mittens on!"
        CANT_PLACE_MITTENS, // "You can't place blocks with mittens on!"

        // === SLAVE SYSTEM ===
        SLAVE_COMMAND, // "Your master commands you to..."
        SLAVE_SHOCK, // "You've been shocked!"
        GPS_ZONE_VIOLATION, // "You've been shocked! Return back to your allowed area!"
        GPS_OWNER_ALERT, // "ALERT: %s is outside the safe zone!"
        SLAVE_JOB_ASSIGNED, // "Job assigned: bring X"
        SLAVE_JOB_COMPLETE, // "Job complete! You are free."
        SLAVE_JOB_FAILED, // "Job failed!"
        SLAVE_JOB_LAST_CHANCE, // "Last chance! Next failure = death"
        SLAVE_JOB_KILLED, // "You were killed for failing"

        // === TIGHTEN ===
        BINDS_TIGHTENED, // "X tightened your binds!"

        // === TOOLS & ITEMS ===
        KEY_CLAIMED, // "Key claimed and linked to %s!"
        KEY_NOT_OWNER, // "You don't own this key!"
        KEY_WRONG_TARGET, // "This key doesn't fit this collar!"
        LOCATOR_CLAIMED, // "Locator claimed!"
        LOCATOR_NOT_OWNER, // "You don't own this locator!"
        LOCATOR_DETECTED, // "Target detected: %s"
        SHOCKER_CLAIMED, // "Shocker claimed!"
        SHOCKER_NOT_OWNER, // "You don't own this shocker!"
        SHOCKER_MODE_SET, // "Shocker mode: %s"
        SHOCKER_TRIGGERED, // "Shocked %s!"
        RAG_DRY, // "The rag is dry - soak it first"
        RAG_SOAKED, // "You soaked the rag with chloroform"
        RAG_EVAPORATED, // "The chloroform has evaporated"

        // === BOUNTY ===
        BOUNTY_CREATED, // "Bounty created on %s!"
        BOUNTY_CLAIMED, // "You claimed the bounty on %s!"
        BOUNTY_EXPIRED, // "Bounty on %s expired"

        // === CELL SYSTEM ===
        PRISONER_ARRIVED, // "X has been placed in your cell"
        PRISONER_ESCAPED, // "X has escaped from your cell!"
        PRISONER_RELEASED, // "X has been released from your cell"
        CELL_BREACH, // "Your cell wall has been breached!"
        CELL_ASSIGNED, // "You have been assigned to X's cell"
        CELL_CREATED, // "Cell created successfully"
        CELL_DELETED, // "Cell deleted"
        CELL_RENAMED, // "Cell renamed to X"

        // === GENERIC ===
        INFO, // Generic info message
        WARNING, // Generic warning
        ERROR, // Generic error
    }

    // TRANSLATION KEYS

    /**
     * Get the translation key for a category.
     * Keys follow the pattern: msg.tiedup.system.&lt;category_lowercase&gt;
     *
     * @param category The message category
     * @return The translation key (for use with Component.translatable)
     */
    public static String getTranslationKey(MessageCategory category) {
        return "msg.tiedup.system." + category.name().toLowerCase();
    }

    /**
     * Get formatting color for a category.
     */
    private static ChatFormatting getCategoryColor(MessageCategory category) {
        return switch (category) {
            // Actions done to you - yellow/gold (attention)
            case
                BEING_TIED,
                BEING_GAGGED,
                BEING_BLINDFOLDED,
                BEING_COLLARED -> ChatFormatting.YELLOW;
            // Completed restraints - red (danger/restriction)
            case
                TIED_UP,
                GAGGED,
                BLINDFOLDED,
                COLLARED,
                EARPLUGS_ON,
                MITTENS_ON,
                ENSLAVED -> ChatFormatting.RED;
            // Kidnapper's perspective - progress (yellow) and complete (green)
            case
                TYING_TARGET,
                GAGGING_TARGET,
                BLINDFOLDING_TARGET,
                COLLARING_TARGET -> ChatFormatting.YELLOW;
            case
                TIED_TARGET,
                GAGGED_TARGET,
                BLINDFOLDED_TARGET,
                COLLARED_TARGET -> ChatFormatting.GREEN;
            // Release - green (positive)
            case
                UNTIED,
                UNGAGGED,
                UNBLINDFOLDED,
                UNCOLLARED,
                FREED -> ChatFormatting.GREEN;
            // Struggle success - green
            case
                STRUGGLE_SUCCESS,
                STRUGGLE_BROKE_FREE,
                STRUGGLE_COLLAR_SUCCESS -> ChatFormatting.GREEN;
            // Struggle fail - gray
            case STRUGGLE_FAIL, STRUGGLE_COLLAR_FAIL -> ChatFormatting.GRAY;
            // Shock - red
            case
                STRUGGLE_SHOCKED,
                SLAVE_SHOCK,
                GPS_ZONE_VIOLATION,
                GPS_OWNER_ALERT -> ChatFormatting.RED;
            // Restrictions - dark red
            case
                CANT_MOVE,
                CANT_ATTACK_TIED,
                CANT_USE_ITEM_TIED,
                CANT_OPEN_INVENTORY,
                CANT_INTERACT_TIED,
                CANT_SPEAK,
                CANT_SEE,
                CANT_BREAK_TIED,
                CANT_PLACE_TIED,
                NO_ELYTRA,
                CANT_ATTACK_MITTENS,
                CANT_USE_ITEM_MITTENS,
                CANT_INTERACT_MITTENS,
                CANT_BREAK_MITTENS,
                CANT_PLACE_MITTENS -> ChatFormatting.DARK_RED;
            // Slave commands - gold
            case SLAVE_COMMAND, SLAVE_JOB_ASSIGNED -> ChatFormatting.GOLD;
            // Slave job complete - green
            case SLAVE_JOB_COMPLETE -> ChatFormatting.GREEN;
            // Slave job failed - red
            case SLAVE_JOB_FAILED -> ChatFormatting.RED;
            // Slave job last chance/killed - dark red (danger)
            case
                SLAVE_JOB_LAST_CHANCE,
                SLAVE_JOB_KILLED -> ChatFormatting.DARK_RED;
            // Tighten - yellow
            case BINDS_TIGHTENED -> ChatFormatting.YELLOW;
            // Tools & Items - various
            case
                KEY_CLAIMED,
                LOCATOR_CLAIMED,
                SHOCKER_CLAIMED,
                RAG_SOAKED -> ChatFormatting.GREEN;
            case
                KEY_NOT_OWNER,
                KEY_WRONG_TARGET,
                LOCATOR_NOT_OWNER,
                SHOCKER_NOT_OWNER,
                RAG_DRY -> ChatFormatting.RED;
            case
                LOCATOR_DETECTED,
                SHOCKER_MODE_SET,
                SHOCKER_TRIGGERED,
                RAG_EVAPORATED -> ChatFormatting.YELLOW;
            // Bounty
            case BOUNTY_CREATED, BOUNTY_CLAIMED -> ChatFormatting.GREEN;
            case BOUNTY_EXPIRED -> ChatFormatting.YELLOW;
            // Cell System
            case
                PRISONER_ARRIVED,
                CELL_CREATED,
                CELL_RENAMED -> ChatFormatting.GREEN;
            case PRISONER_ESCAPED, CELL_BREACH -> ChatFormatting.RED;
            case PRISONER_RELEASED, CELL_DELETED -> ChatFormatting.YELLOW;
            case CELL_ASSIGNED -> ChatFormatting.GOLD;
            // Generic
            case INFO -> ChatFormatting.WHITE;
            case WARNING -> ChatFormatting.YELLOW;
            case ERROR -> ChatFormatting.RED;
        };
    }

    // SEND METHODS - TO SINGLE PLAYER

    /**
     * Send a system message to a player's action bar.
     * Uses translatable category with entity name as argument.
     *
     * @param player The player to send to
     * @param category The message category
     * @param actor The entity performing the action (for %1$s replacement)
     */
    public static void sendToPlayer(
        Player player,
        MessageCategory category,
        Entity actor
    ) {
        if (player == null) return;

        String actorName = actor != null ? getEntityName(actor) : "Someone";
        MutableComponent component = Component.translatable(
            getTranslationKey(category), actorName
        ).withStyle(style -> style.withColor(getCategoryColor(category)));

        player.displayClientMessage(component, true);

        TiedUpMod.LOGGER.debug(
            "[SystemMessage] -> {}: {} ({})",
            player.getName().getString(),
            getTranslationKey(category),
            actorName
        );
    }

    /**
     * Send a system message to a player's action bar.
     * Uses translatable category without arguments.
     *
     * @param player The player to send to
     * @param category The message category
     */
    public static void sendToPlayer(Player player, MessageCategory category) {
        if (player == null) return;

        MutableComponent component = Component.translatable(
            getTranslationKey(category)
        ).withStyle(style -> style.withColor(getCategoryColor(category)));

        player.displayClientMessage(component, true);

        TiedUpMod.LOGGER.debug(
            "[SystemMessage] -> {}: {}",
            player.getName().getString(),
            getTranslationKey(category)
        );
    }

    /**
     * Send a custom system message to a player's action bar.
     * Uses literal text (for dynamic/non-translatable messages).
     *
     * @param player The player to send to
     * @param message The message to send
     * @param color The color to use
     */
    public static void sendToPlayer(
        Player player,
        String message,
        ChatFormatting color
    ) {
        if (player == null || message == null) return;

        MutableComponent component = Component.literal(message).withStyle(
            style -> style.withColor(color)
        );

        player.displayClientMessage(component, true);

        TiedUpMod.LOGGER.debug(
            "[SystemMessage] -> {}: {}",
            player.getName().getString(),
            message
        );
    }

    /**
     * Send a custom system message to a player's CHAT.
     * Uses literal text (for dynamic/non-translatable messages).
     *
     * @param player The player to send to
     * @param message The message to send
     * @param color The color to use
     */
    public static void sendChatToPlayer(
        Player player,
        String message,
        ChatFormatting color
    ) {
        if (player == null || message == null) return;

        MutableComponent component = Component.literal(message).withStyle(
            style -> style.withColor(color)
        );

        player.displayClientMessage(component, false);

        TiedUpMod.LOGGER.debug(
            "[SystemMessage-Chat] -> {}: {}",
            player.getName().getString(),
            message
        );
    }

    /**
     * Send a system message to a player's CHAT using a translatable category.
     */
    public static void sendChatToPlayer(
        Player player,
        MessageCategory category
    ) {
        if (player == null) return;
        MutableComponent component = Component.translatable(
            getTranslationKey(category)
        ).withStyle(style -> style.withColor(getCategoryColor(category)));
        player.displayClientMessage(component, false);
    }

    /**
     * Send a system message to a player's CHAT using a translatable category and actor.
     */
    public static void sendChatToPlayer(
        Player player,
        MessageCategory category,
        Entity actor
    ) {
        if (player == null) return;
        String actorName = actor != null ? getEntityName(actor) : "Someone";
        MutableComponent component = Component.translatable(
            getTranslationKey(category), actorName
        ).withStyle(style -> style.withColor(getCategoryColor(category)));
        player.displayClientMessage(component, false);
    }

    /**
     * Send a custom message with category formatting.
     *
     * @param player The player to send to
     * @param category The category (for color)
     * @param customMessage The custom message text (literal, not translatable)
     */
    public static void sendToPlayer(
        Player player,
        MessageCategory category,
        String customMessage
    ) {
        sendToPlayer(player, customMessage, getCategoryColor(category));
    }

    /**
     * Send a translatable message with string arguments.
     * Uses the category's translation key and color.
     *
     * @param player The player to send to
     * @param category The message category
     * @param args Arguments for the translation (replaces %1$s, %2$s, etc.)
     */
    public static void sendTranslatable(
        Player player,
        MessageCategory category,
        Object... args
    ) {
        if (player == null) return;
        MutableComponent component = Component.translatable(
            getTranslationKey(category), args
        ).withStyle(style -> style.withColor(getCategoryColor(category)));
        player.displayClientMessage(component, true);
    }

    /**
     * Send a translatable message with resistance info appended.
     *
     * @param player The player to send to
     * @param category The message category
     * @param resistance The current resistance value
     */
    public static void sendWithResistance(
        Player player,
        MessageCategory category,
        int resistance
    ) {
        if (player == null) return;

        MutableComponent component = Component.translatable(
            getTranslationKey(category)
        ).append(
            Component.translatable("msg.tiedup.system.resistance_suffix", resistance)
        ).withStyle(style -> style.withColor(getCategoryColor(category)));

        player.displayClientMessage(component, true);
    }

    // SEND METHODS - TO NEARBY PLAYERS

    /**
     * Send a system message to all players within radius.
     * The message is from the perspective of the actor.
     *
     * @param actor The entity performing the action
     * @param target The target of the action (if player, gets special message)
     * @param category The message category
     * @param radius The radius in blocks
     */
    public static void sendToNearby(
        Entity actor,
        LivingEntity target,
        MessageCategory category,
        int radius
    ) {
        if (actor == null) return;

        List<Player> players = actor
            .level()
            .getEntitiesOfClass(
                Player.class,
                actor.getBoundingBox().inflate(radius)
            );

        for (Player player : players) {
            if (player == target) {
                // Target gets the "done to you" message
                sendToPlayer(player, category, actor);
            }
            // Other nearby players could get a different perspective
            // For now, only the target gets the message
        }
    }

    /**
     * Send a system message to the target if they're a player.
     *
     * @param actor The entity performing the action
     * @param target The target (only receives if Player)
     * @param category The message category
     */
    public static void sendToTarget(
        Entity actor,
        LivingEntity target,
        MessageCategory category
    ) {
        if (target instanceof Player player) {
            sendToPlayer(player, category, actor);
        }
    }

    /**
     * Send a custom message to the target if they're a player.
     *
     * @param actor The entity performing the action (for logging)
     * @param target The target (only receives if Player)
     * @param message The message to send
     * @param color The color to use
     */
    public static void sendToTarget(
        Entity actor,
        LivingEntity target,
        String message,
        ChatFormatting color
    ) {
        if (target instanceof Player player) {
            sendToPlayer(player, message, color);
        }
    }

    // CONVENIENCE METHODS

    /**
     * Send "X is tying you up!" to target.
     */
    public static void sendBeingTied(Entity actor, LivingEntity target) {
        sendToTarget(actor, target, MessageCategory.BEING_TIED);
    }

    /**
     * Send "You are tying X..." to the kidnapper.
     */
    public static void sendTyingTarget(Entity kidnapper, LivingEntity target) {
        if (kidnapper instanceof Player player) {
            TiedUpMod.LOGGER.info(
                "[SystemMessage] Sending TYING_TARGET to {} about {}",
                player.getName().getString(),
                target.getName().getString()
            );
            sendToPlayer(player, MessageCategory.TYING_TARGET, target);
        }
    }

    /**
     * Send "X tied you up!" to target.
     */
    public static void sendTiedUp(Entity actor, LivingEntity target) {
        sendToTarget(actor, target, MessageCategory.TIED_UP);
    }

    /**
     * Send "You tied X!" to the kidnapper.
     */
    public static void sendTiedTarget(Entity kidnapper, LivingEntity target) {
        if (kidnapper instanceof Player player) {
            sendToPlayer(player, MessageCategory.TIED_TARGET, target);
        }
    }

    /**
     * Send "X is gagging you!" to target.
     */
    public static void sendBeingGagged(Entity actor, LivingEntity target) {
        sendToTarget(actor, target, MessageCategory.BEING_GAGGED);
    }

    /**
     * Send "X gagged you!" to target.
     */
    public static void sendGagged(Entity actor, LivingEntity target) {
        sendToTarget(actor, target, MessageCategory.GAGGED);
    }

    /**
     * Send "You have been enslaved by X!" to target.
     */
    public static void sendEnslaved(Entity actor, LivingEntity target) {
        sendToTarget(actor, target, MessageCategory.ENSLAVED);
    }

    /**
     * Send "You have been freed!" to target.
     */
    public static void sendFreed(LivingEntity target) {
        if (target instanceof Player player) {
            sendToPlayer(player, MessageCategory.FREED);
        }
    }

    /**
     * Send restriction message (can't do X while tied).
     */
    public static void sendRestriction(
        Player player,
        MessageCategory restrictionCategory
    ) {
        sendToPlayer(player, restrictionCategory);
    }

    /**
     * Send a shock message to target.
     */
    public static void sendShocked(LivingEntity target) {
        if (target instanceof Player player) {
            sendToPlayer(player, MessageCategory.SLAVE_SHOCK);
        }
    }

    /**
     * Send binds tightened message.
     */
    public static void sendBindsTightened(Entity actor, LivingEntity target) {
        sendToTarget(actor, target, MessageCategory.BINDS_TIGHTENED);
    }

    /**
     * Send job assigned message with item name.
     */
    public static void sendJobAssigned(Player player, String itemName) {
        if (player == null) return;
        MutableComponent component = Component.translatable(
            getTranslationKey(MessageCategory.SLAVE_JOB_ASSIGNED), itemName
        ).withStyle(style -> style.withColor(getCategoryColor(MessageCategory.SLAVE_JOB_ASSIGNED)));
        player.displayClientMessage(component, true);
    }

    // UTILITY

    /**
     * Get display name for an entity.
     */
    private static String getEntityName(Entity entity) {
        if (entity == null) return "Someone";

        // Check for custom damsel name
        if (entity instanceof com.tiedup.remake.entities.EntityDamsel damsel) {
            String damselName = damsel.getNpcName();
            if (damselName != null && !damselName.isEmpty()) {
                return damselName;
            }
        }

        return entity.getName().getString();
    }
}
