package com.tiedup.remake.dialogue;

import com.tiedup.remake.personality.PersonalityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import org.jetbrains.annotations.Nullable;

/**
 * Context information for dialogue selection.
 * Holds all relevant state needed to match dialogue conditions.
 *
 * Personality System: Data-driven dialogue
 * Universal NPC Support: Extended for all speaker types
 */
public class DialogueContext {

    // Speaker type for dialogue routing
    private final SpeakerType speakerType;

    private final PersonalityType personality;
    private final int mood;

    // Kidnapper-specific context
    @Nullable
    private final String kidnapperTheme;

    // Merchant-specific context
    @Nullable
    private final String merchantMode;

    // Variable substitution data
    @Nullable
    private final String npcName;

    @Nullable
    private final String playerName;

    @Nullable
    private final String masterName;

    @Nullable
    private final String targetName;

    // Additional state
    private final boolean isBound;
    private final boolean isGagged;
    private final boolean isBlindfold;
    private final boolean hasCollar;
    private final float hunger;

    private DialogueContext(Builder builder) {
        this.speakerType = builder.speakerType;
        this.personality = builder.personality;
        this.mood = builder.mood;
        this.kidnapperTheme = builder.kidnapperTheme;
        this.merchantMode = builder.merchantMode;
        this.npcName = builder.npcName;
        this.playerName = builder.playerName;
        this.masterName = builder.masterName;
        this.targetName = builder.targetName;
        this.isBound = builder.isBound;
        this.isGagged = builder.isGagged;
        this.isBlindfold = builder.isBlindfold;
        this.hasCollar = builder.hasCollar;
        this.hunger = builder.hunger;
    }

    // --- Getters for condition matching ---

    /**
     * Get the speaker type for dialogue routing.
     */
    public SpeakerType getSpeakerType() {
        return speakerType;
    }

    public PersonalityType getPersonality() {
        return personality;
    }

    /**
     * Get the kidnapper theme (for theme-based personalities).
     * Only relevant for kidnapper-type speakers.
     */
    @Nullable
    public String getKidnapperTheme() {
        return kidnapperTheme;
    }

    /**
     * Get the merchant mode (MERCHANT or HOSTILE).
     * Only relevant for merchant speakers.
     */
    @Nullable
    public String getMerchantMode() {
        return merchantMode;
    }

    public int getMood() {
        return mood;
    }

    // --- Getters for variable substitution ---

    @Nullable
    public String getNpcName() {
        return npcName;
    }

    @Nullable
    public String getPlayerName() {
        return playerName;
    }

    @Nullable
    public String getMasterName() {
        return masterName;
    }

    @Nullable
    public String getTargetName() {
        return targetName;
    }

    public boolean isBound() {
        return isBound;
    }

    public boolean isGagged() {
        return isGagged;
    }

    public boolean isBlindfold() {
        return isBlindfold;
    }

    public boolean hasCollar() {
        return hasCollar;
    }

    public float getHunger() {
        return hunger;
    }

    /**
     * Get mood as a string descriptor.
     */
    public String getMoodString() {
        if (mood >= 70) return "happy";
        if (mood >= 40) return "neutral";
        if (mood >= 10) return "sad";
        return "miserable";
    }

    /**
     * Get hunger as a string descriptor.
     */
    public String getHungerString() {
        if (hunger >= 70) return "full";
        if (hunger >= 30) return "hungry";
        return "starving";
    }

    /**
     * Substitute variables in dialogue text.
     *
     * @param text Text with placeholders like {player}, {npc}, etc.
     * @return Text with placeholders replaced
     */
    public String substituteVariables(String text) {
        String result = text;

        // Entity names
        if (npcName != null) {
            result = result.replace("{npc}", npcName);
        }
        if (playerName != null) {
            result = result.replace("{player}", playerName);
        }
        if (masterName != null) {
            result = result.replace("{master}", masterName);
        }
        if (targetName != null) {
            result = result.replace("{target}", targetName);
        }

        // State variables
        result = result.replace("{mood}", getMoodString());
        result = result.replace("{hunger}", getHungerString());
        result = result.replace(
            "{personality}",
            personality.name().toLowerCase()
        );

        return result;
    }

    public static Builder builder() {
        return new Builder();
    }

    /**
     * Builder for DialogueContext.
     */
    public static class Builder {

        private SpeakerType speakerType = SpeakerType.DAMSEL;
        private PersonalityType personality = PersonalityType.CALM;
        private int mood = 50;
        private String kidnapperTheme = null;
        private String merchantMode = null;
        private String npcName = null;
        private String playerName = null;
        private String masterName = null;
        private String targetName = null;
        private boolean isBound = false;
        private boolean isGagged = false;
        private boolean isBlindfold = false;
        private boolean hasCollar = false;
        private float hunger = 100f;

        public Builder speakerType(SpeakerType speakerType) {
            this.speakerType = speakerType;
            return this;
        }

        public Builder personality(PersonalityType personality) {
            this.personality = personality;
            return this;
        }

        public Builder kidnapperTheme(String theme) {
            this.kidnapperTheme = theme;
            return this;
        }

        public Builder merchantMode(String mode) {
            this.merchantMode = mode;
            return this;
        }

        public Builder mood(int mood) {
            this.mood = mood;
            return this;
        }

        public Builder npcName(String name) {
            this.npcName = name;
            return this;
        }

        public Builder playerName(String name) {
            this.playerName = name;
            return this;
        }

        public Builder masterName(String name) {
            this.masterName = name;
            return this;
        }

        public Builder targetName(String name) {
            this.targetName = name;
            return this;
        }

        public Builder bound(boolean bound) {
            this.isBound = bound;
            return this;
        }

        public Builder gagged(boolean gagged) {
            this.isGagged = gagged;
            return this;
        }

        public Builder blindfold(boolean blindfold) {
            this.isBlindfold = blindfold;
            return this;
        }

        public Builder hasCollar(boolean collar) {
            this.hasCollar = collar;
            return this;
        }

        public Builder hunger(float hunger) {
            this.hunger = hunger;
            return this;
        }

        /**
         * Set player info from a Player entity.
         */
        public Builder fromPlayer(Player player) {
            this.playerName = player.getName().getString();
            return this;
        }

        /**
         * Set target info from a LivingEntity.
         */
        public Builder fromTarget(LivingEntity target) {
            this.targetName = target.getName().getString();
            return this;
        }

        public DialogueContext build() {
            return new DialogueContext(this);
        }

        /**
         * Build from an IDialogueSpeaker.
         * Automatically sets speakerType, personality, mood, and npcName.
         *
         * @param speaker The dialogue speaker
         * @param player The player interacting (can be null)
         * @return Builder with speaker data applied
         */
        public Builder fromSpeaker(
            IDialogueSpeaker speaker,
            @Nullable Player player
        ) {
            this.speakerType = speaker.getSpeakerType();
            this.npcName = speaker.getDialogueName();
            this.mood = speaker.getSpeakerMood();

            if (speaker.getSpeakerPersonality() != null) {
                this.personality = speaker.getSpeakerPersonality();
            }

            if (player != null) {
                this.playerName = player.getName().getString();
            }

            return this;
        }
    }
}
