package com.tiedup.remake.dialogue;

import com.tiedup.remake.entities.EntityDamsel;
import com.tiedup.remake.util.MessageDispatcher;
import java.util.List;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;

/**
 * Complete dialogue system for EntityDamsel and EntityKidnapper.
 *
 *
 * Features:
 * - Multiple dialogue variants per action category
 * - Integration with GagTalkManager for gagged NPCs
 * - Formatted messages with entity name
 * - Action messages vs speech messages
 * - Radius-based broadcasting
 */
public class EntityDialogueManager {

    // DIALOGUE CATEGORIES

    /**
     * Dialogue categories for different NPC actions.
     */
    public enum DialogueCategory {
        // === KIDNAPPER CAPTURE SEQUENCE ===
        CAPTURE_START, // When kidnapper starts chasing
        CAPTURE_APPROACHING, // While approaching target
        CAPTURE_CHASE, // When pursuing an escaped captive
        CAPTURE_TYING, // While tying up target
        CAPTURE_TIED, // After target is tied
        CAPTURE_GAGGING, // While gagging target
        CAPTURE_GAGGED, // After target is gagged
        CAPTURE_ENSLAVED, // After enslaving target
        CAPTURE_ESCAPE, // When captive escapes

        // === SLAVE MANAGEMENT ===
        SLAVE_TALK_RESPONSE, // When slave tries to talk
        SLAVE_STRUGGLE, // When slave struggles
        SLAVE_TRANSPORT, // When transporting slave
        SLAVE_ARRIVE_PRISON, // When arriving at prison
        SLAVE_TIED_TO_POLE, // When tying slave to pole
        PUNISH, // When punishing a recaptured or misbehaving captive

        // === SALE SYSTEM ===
        SALE_WAITING, // Waiting for buyer
        SALE_ANNOUNCE, // Announcing sale
        SALE_OFFER, // Offering to sell to a passing player (needs %s for player name and %s for price)
        SALE_COMPLETE, // Sale completed
        SALE_ABANDONED, // When kidnapper abandons captive (solo mode)
        SALE_KEPT, // When kidnapper decides to keep captive (solo mode)

        // === JOB SYSTEM ===
        JOB_ASSIGNED, // Giving job to slave
        JOB_HURRY, // Urging slave to hurry
        JOB_COMPLETE, // Job completed successfully
        JOB_FAILED, // Job failed
        JOB_LAST_CHANCE, // Warning before killing
        JOB_KILL, // Killing the slave for failure

        // === COMBAT/ATTACK ===
        ATTACKED_RESPONSE, // When attacked by someone
        ATTACK_SLAVE, // When slave attacks

        // === DAMSEL SPECIFIC ===
        DAMSEL_PANIC, // When damsel is scared
        DAMSEL_FLEE, // When damsel flees
        DAMSEL_CAPTURED, // When damsel is captured
        DAMSEL_FREED, // When damsel is freed
        DAMSEL_GREETING, // Greeting nearby players
        DAMSEL_IDLE, // Random idle chatter
        DAMSEL_CALL_FOR_HELP, // When tied damsel sees a player nearby (needs %s for player name)

        // === GENERAL ===
        FREED, // When freeing someone
        GOODBYE, // Saying goodbye
        GET_OUT, // Telling someone to leave
        GENERIC_THREAT, // Generic threatening line
        GENERIC_TAUNT, // Generic taunting line

        // === PERSONALITY SYSTEM (Phase E) ===
        COMMAND_ACCEPT, // When NPC accepts a command
        COMMAND_REFUSE, // When NPC refuses a command
        COMMAND_HESITATE, // When NPC hesitates before command

        // === DISCIPLINE SYSTEM (Training V2) ===
        PRAISE_RESPONSE, // When NPC is praised
        SCOLD_RESPONSE, // When NPC is scolded
        THREATEN_RESPONSE, // When NPC is threatened
        NEED_HUNGRY, // When NPC is hungry
        NEED_TIRED, // When NPC is tired
        NEED_UNCOMFORTABLE, // When NPC is uncomfortable
        NEED_DIGNITY_LOW, // When NPC has low dignity
        PERSONALITY_HINT_TIMID, // Hint for TIMID personality
        PERSONALITY_HINT_GENTLE, // Hint for GENTLE personality
        PERSONALITY_HINT_SUBMISSIVE, // Hint for SUBMISSIVE personality
        PERSONALITY_HINT_CALM, // Hint for CALM personality
        PERSONALITY_HINT_CURIOUS, // Hint for CURIOUS personality
        PERSONALITY_HINT_PROUD, // Hint for PROUD personality
        PERSONALITY_HINT_FIERCE, // Hint for FIERCE personality
        PERSONALITY_HINT_DEFIANT, // Hint for DEFIANT personality
        PERSONALITY_HINT_PLAYFUL, // Hint for PLAYFUL personality
        PERSONALITY_HINT_MASOCHIST, // Hint for MASOCHIST personality
        PERSONALITY_HINT_SADIST, // Hint for SADIST personality (kidnappers)
    }

    // DIALOGUE RETRIEVAL (Data-Driven Only)

    /**
     * Get random dialogue for a category using the data-driven system.
     * All dialogues are now loaded from JSON files.
     *
     * @param category The dialogue category
     * @return Dialogue text, or a fallback message if not found
     */
    public static String getDialogue(DialogueCategory category) {
        // Use data-driven system with default context
        if (com.tiedup.remake.dialogue.DialogueManager.isInitialized()) {
            String dialogueId =
                com.tiedup.remake.dialogue.DialogueBridge.categoryToDialogueId(
                    category
                );
            com.tiedup.remake.dialogue.DialogueContext defaultContext =
                com.tiedup.remake.dialogue.DialogueContext.builder()
                    .personality(
                        com.tiedup.remake.personality.PersonalityType.CALM
                    )
                    .mood(50)
                    .build();

            String text =
                com.tiedup.remake.dialogue.DialogueManager.getDialogue(
                    dialogueId,
                    defaultContext
                );
            if (text != null) {
                return text;
            }
        }

        // Fallback for uninitialized system
        com.tiedup.remake.core.TiedUpMod.LOGGER.warn(
            "[EntityDialogueManager] Data-driven dialogue not found for category: {}",
            category.name()
        );
        return "[" + category.name() + "]";
    }

    /**
     * Get dialogue for a category using the data-driven system.
     * Uses entity context for personality-aware dialogue selection.
     *
     * @param entity The entity speaking
     * @param player The player (can be null)
     * @param category The dialogue category
     * @return Dialogue text
     */
    public static String getDialogue(
        EntityDamsel entity,
        Player player,
        DialogueCategory category
    ) {
        // Always use data-driven system
        String dataDriven =
            com.tiedup.remake.dialogue.DialogueBridge.getDataDrivenDialogue(
                entity,
                player,
                category
            );
        if (dataDriven != null) {
            return dataDriven;
        }

        // Fallback to category-only lookup (no entity context)
        return getDialogue(category);
    }

    // MESSAGE SENDING METHODS

    /**
     * Send a dialogue message to a specific player.
     * Format: *EntityName* : message
     * Uses data-driven dialogue system if available.
     *
     * @param entity The entity speaking
     * @param player The player receiving the message
     * @param category The dialogue category
     */
    public static void talkTo(
        EntityDamsel entity,
        Player player,
        DialogueCategory category
    ) {
        // Use data-driven dialogue when available
        talkTo(entity, player, getDialogue(entity, player, category));
    }

    /**
     * Send a custom message to a specific player.
     * Delegates formatting, gag talk, and earplug handling to MessageDispatcher.
     *
     * @param entity The entity speaking
     * @param player The player receiving the message
     * @param message The message to send
     */
    public static void talkTo(
        EntityDamsel entity,
        Player player,
        String message
    ) {
        if (entity == null || player == null || message == null) return;
        if (entity.level().isClientSide()) return;
        if (!(player instanceof ServerPlayer)) return;
        MessageDispatcher.talkTo(entity, player, message);
    }

    /**
     * Send a dialogue message using a dialogue ID.
     * Resolves the ID to actual text via DialogueManager.
     *
     * @param entity The entity speaking
     * @param player The player receiving the message
     * @param dialogueId The dialogue ID (e.g., "action.whip")
     */
    public static void talkByDialogueId(
        EntityDamsel entity,
        Player player,
        String dialogueId
    ) {
        if (entity == null || player == null || dialogueId == null) return;
        if (entity.level().isClientSide()) return;

        if (!com.tiedup.remake.dialogue.DialogueManager.isInitialized()) {
            talkTo(entity, player, "[Dialogue system not ready]");
            return;
        }

        // Build context and resolve dialogue text
        com.tiedup.remake.dialogue.DialogueContext context =
            com.tiedup.remake.dialogue.DialogueBridge.buildContext(
                entity,
                player
            );

        String text = com.tiedup.remake.dialogue.DialogueManager.getDialogue(
            dialogueId,
            context
        );

        if (text == null) {
            text = "[Missing: " + dialogueId + "]";
            com.tiedup.remake.core.TiedUpMod.LOGGER.warn(
                "[EntityDialogueManager] Missing dialogue for ID: {} with personality: {}",
                dialogueId,
                context.getPersonality()
            );
        }

        talkTo(entity, player, text);
    }

    /**
     * Send an action message to a specific player.
     * Format: EntityName action
     * Uses data-driven dialogue system if available.
     *
     * @param entity The entity performing the action
     * @param player The player receiving the message
     * @param category The dialogue category
     */
    public static void actionTo(
        EntityDamsel entity,
        Player player,
        DialogueCategory category
    ) {
        // Use data-driven dialogue when available
        actionTo(entity, player, getDialogue(entity, player, category));
    }

    /**
     * Send a custom action message to a specific player.
     * Delegates formatting and earplug handling to MessageDispatcher.
     *
     * @param entity The entity performing the action
     * @param player The player receiving the message
     * @param action The action description
     */
    public static void actionTo(
        EntityDamsel entity,
        Player player,
        String action
    ) {
        if (entity == null || player == null || action == null) return;
        if (entity.level().isClientSide()) return;
        if (!(player instanceof ServerPlayer)) return;
        MessageDispatcher.actionTo(entity, player, action);
    }

    /**
     * Talk to all players within a radius.
     * Builds proper context per player for variable substitution.
     *
     * @param entity The entity speaking
     * @param category The dialogue category
     * @param radius The radius in blocks
     */
    public static void talkToNearby(
        EntityDamsel entity,
        DialogueCategory category,
        int radius
    ) {
        if (entity == null) return;

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

        for (Player player : players) {
            // Use the context-aware dialogue lookup for proper {player} substitution
            String dialogue = getDialogue(entity, player, category);
            talkTo(entity, player, dialogue);
        }
    }

    /**
     * Talk to all players within a radius with a custom message.
     *
     * @param entity The entity speaking
     * @param message The message to send
     * @param radius The radius in blocks
     */
    public static void talkToNearby(
        EntityDamsel entity,
        String message,
        int radius
    ) {
        if (entity == null || message == null) return;

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

        for (Player player : players) {
            talkTo(entity, player, message);
        }
    }

    /**
     * Send an action message to all players within a radius.
     * Builds proper context per player for variable substitution.
     *
     * @param entity The entity performing the action
     * @param category The dialogue category
     * @param radius The radius in blocks
     */
    public static void actionToNearby(
        EntityDamsel entity,
        DialogueCategory category,
        int radius
    ) {
        if (entity == null) return;

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

        for (Player player : players) {
            // Use the context-aware dialogue lookup for proper {player} substitution
            String action = getDialogue(entity, player, category);
            actionTo(entity, player, action);
        }
    }

    /**
     * Send a custom action message to all players within a radius.
     *
     * @param entity The entity performing the action
     * @param action The action description
     * @param radius The radius in blocks
     */
    public static void actionToNearby(
        EntityDamsel entity,
        String action,
        int radius
    ) {
        if (entity == null || action == null) return;

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

        for (Player player : players) {
            actionTo(entity, player, action);
        }
    }

    // CONVENIENCE METHODS

    /**
     * Make entity say something to their target (if player).
     */
    public static void talkToTarget(
        EntityDamsel entity,
        LivingEntity target,
        DialogueCategory category
    ) {
        if (target instanceof Player player) {
            talkTo(entity, player, category);
        }
    }

    /**
     * Make entity say a custom message to their target (if player).
     */
    public static void talkToTarget(
        EntityDamsel entity,
        LivingEntity target,
        String message
    ) {
        if (target instanceof Player player) {
            talkTo(entity, player, message);
        }
    }

    /**
     * Make entity perform action to their target (if player).
     */
    public static void actionToTarget(
        EntityDamsel entity,
        LivingEntity target,
        DialogueCategory category
    ) {
        if (target instanceof Player player) {
            actionTo(entity, player, category);
        }
    }

    /**
     * Make entity perform custom action to their target (if player).
     */
    public static void actionToTarget(
        EntityDamsel entity,
        LivingEntity target,
        String action
    ) {
        if (target instanceof Player player) {
            actionTo(entity, player, action);
        }
    }

    // COMPOUND MESSAGES

    /**
     * Get a dialogue for job assignment with item name.
     */
    public static String getJobAssignmentDialogue(String itemName) {
        return getDialogue(DialogueCategory.JOB_ASSIGNED) + itemName;
    }

    /**
     * Get a call for help dialogue with player name.
     *
     * @deprecated Use {@link #callForHelp(EntityDamsel, Player)} which builds proper context.
     */
    @Deprecated
    public static String getCallForHelpDialogue(String playerName) {
        // Legacy fallback - manually substitute {player}
        String text = getDialogue(DialogueCategory.DAMSEL_CALL_FOR_HELP);
        return text.replace("{player}", playerName);
    }

    /**
     * Get a sale offer dialogue with player name and price.
     * The {player} placeholder is the buyer, {target} is the price.
     *
     * @param playerName The buyer's name
     * @param price The price as a display string (e.g., "50 gold")
     * @return Formatted dialogue text
     */
    public static String getSaleOfferDialogue(String playerName, String price) {
        // Substitute placeholders manually since we don't have full context
        String text = getDialogue(DialogueCategory.SALE_OFFER);
        text = text.replace("{player}", playerName);
        text = text.replace("{target}", price); // {target} is used for price in sale dialogues
        return text;
    }

    /**
     * Make a tied damsel call for help to a nearby player.
     * Pre-conditions (tied, slave, not gagged) should be checked by caller.
     *
     * @param damsel The damsel calling for help
     * @param targetPlayer The player to call for help
     */
    public static void callForHelp(EntityDamsel damsel, Player targetPlayer) {
        if (damsel == null || targetPlayer == null) return;

        // Use context-aware dialogue for proper {player} substitution
        String message = getDialogue(
            damsel,
            targetPlayer,
            DialogueCategory.DAMSEL_CALL_FOR_HELP
        );
        talkTo(damsel, targetPlayer, message);
    }

    /**
     * Get a sale announcement with coordinates.
     */
    public static String getSaleAnnouncement(
        EntityDamsel entity,
        String slaveName
    ) {
        return String.format(
            "%s is selling %s at coordinates: %d, %d, %d",
            entity.getNpcName(),
            slaveName,
            (int) entity.getX(),
            (int) entity.getY(),
            (int) entity.getZ()
        );
    }

    // PERSONALITY SYSTEM HELPERS

    /**
     * Get personality hint dialogue based on personality type name.
     *
     * @param personalityTypeName The name of the personality type (from PersonalityType enum)
     * @return The hint dialogue category, or null if unknown
     */
    public static DialogueCategory getPersonalityHintCategory(
        String personalityTypeName
    ) {
        return switch (personalityTypeName.toUpperCase()) {
            case "TIMID" -> DialogueCategory.PERSONALITY_HINT_TIMID;
            case "GENTLE" -> DialogueCategory.PERSONALITY_HINT_GENTLE;
            case "SUBMISSIVE" -> DialogueCategory.PERSONALITY_HINT_SUBMISSIVE;
            case "CALM" -> DialogueCategory.PERSONALITY_HINT_CALM;
            case "CURIOUS" -> DialogueCategory.PERSONALITY_HINT_CURIOUS;
            case "PROUD" -> DialogueCategory.PERSONALITY_HINT_PROUD;
            case "FIERCE" -> DialogueCategory.PERSONALITY_HINT_FIERCE;
            case "DEFIANT" -> DialogueCategory.PERSONALITY_HINT_DEFIANT;
            case "PLAYFUL" -> DialogueCategory.PERSONALITY_HINT_PLAYFUL;
            case "MASOCHIST" -> DialogueCategory.PERSONALITY_HINT_MASOCHIST;
            case "SADIST" -> DialogueCategory.PERSONALITY_HINT_SADIST;
            default -> null;
        };
    }

    /**
     * Show a personality hint action to a player.
     * Used when discovery level is GLIMPSE to give behavioral cues.
     *
     * @param entity The entity with the personality
     * @param player The player to show the hint to
     * @param personalityTypeName The personality type name
     */
    public static void showPersonalityHint(
        EntityDamsel entity,
        Player player,
        String personalityTypeName
    ) {
        DialogueCategory hintCategory = getPersonalityHintCategory(
            personalityTypeName
        );
        if (hintCategory != null) {
            actionTo(entity, player, hintCategory);
        }
    }

    /**
     * Get dialogue for command response based on acceptance.
     *
     * @param accepted true if command was accepted, false if refused
     * @param hesitated true if the NPC hesitated before responding
     * @return The appropriate dialogue
     */
    public static String getCommandResponseDialogue(
        boolean accepted,
        boolean hesitated
    ) {
        if (!accepted) {
            return getDialogue(DialogueCategory.COMMAND_REFUSE);
        }
        if (hesitated) {
            return getDialogue(DialogueCategory.COMMAND_HESITATE);
        }
        return getDialogue(DialogueCategory.COMMAND_ACCEPT);
    }

    /**
     * Get dialogue for a specific need when it's critically low.
     *
     * @param needType The type of need ("hunger", "comfort", "rest", "dignity")
     * @return The appropriate dialogue category, or null if unknown
     */
    public static DialogueCategory getNeedDialogueCategory(String needType) {
        return switch (needType.toLowerCase()) {
            case "hunger" -> DialogueCategory.NEED_HUNGRY;
            case "rest" -> DialogueCategory.NEED_TIRED;
            case "comfort" -> DialogueCategory.NEED_UNCOMFORTABLE;
            case "dignity" -> DialogueCategory.NEED_DIGNITY_LOW;
            default -> null;
        };
    }
}
