package com.tiedup.remake.compat.mca.personality;

import com.tiedup.remake.compat.mca.MCACompat;
import com.tiedup.remake.core.TiedUpMod;
import java.lang.reflect.Method;
import java.util.Random;
import net.minecraft.world.entity.LivingEntity;

/**
 * Manages MCA mood modifications during bondage events.
 *
 * <p>MCA mood system:
 * <ul>
 *   <li>getMoodValue() -&gt; int (typically -15 to 15)</li>
 *   <li>modifyMoodValue(int) -&gt; void</li>
 * </ul>
 *
 * <p>Mood changes are personality-dependent. Some personalities
 * enjoy being restrained (FLIRTY), while others hate it (CONFIDENT, SENSITIVE).
 */
public class MCAMoodManager {

    private static final MCAMoodManager INSTANCE = new MCAMoodManager();
    private static final Random RANDOM = new Random();

    // Cached reflection methods
    private Method modifyMoodMethod;
    private Method getMoodValueMethod;
    private boolean reflectionInitialized = false;

    public static MCAMoodManager getInstance() {
        return INSTANCE;
    }

    private MCAMoodManager() {}

    // EVENT HANDLERS

    /**
     * Called when villager is tied up.
     * Mood change depends on personality and trait.
     */
    public void onTied(LivingEntity entity) {
        if (!MCACompat.isMCAVillager(entity)) return;

        MCAPersonality personality =
            MCAPersonalityManager.getInstance().getPersonality(entity);
        TiedUpTrait trait = MCAPersonalityManager.getInstance().getTrait(
            entity
        );

        int moodChange;
        if (personality.isUnpredictable()) {
            // ODD: random mood change
            moodChange = RANDOM.nextInt(11) - 5; // -5 to +5
        } else {
            moodChange = TiedUpTrait.getCombinedMoodTied(personality, trait);
        }

        modifyMood(entity, moodChange);

        TiedUpMod.LOGGER.debug(
            "[MCA Mood] {} tied: mood {} (personality={}, trait={})",
            entity.getName().getString(),
            moodChange >= 0 ? "+" + moodChange : moodChange,
            personality.getMcaId(),
            trait.getId()
        );
    }

    /**
     * Called when villager is freed.
     * Generally positive, but personality affects amount.
     */
    public void onFreed(LivingEntity entity) {
        if (!MCACompat.isMCAVillager(entity)) return;

        MCAPersonality personality =
            MCAPersonalityManager.getInstance().getPersonality(entity);
        TiedUpTrait trait = MCAPersonalityManager.getInstance().getTrait(
            entity
        );

        int moodChange;
        if (personality.isUnpredictable()) {
            moodChange = RANDOM.nextInt(11) - 3; // -3 to +7 (slightly positive bias)
        } else {
            // Base positive + personality modifier
            moodChange = switch (personality) {
                case SENSITIVE -> +7;
                case FRIENDLY -> +6;
                case SHY, CONFIDENT -> +5;
                case GRUMPY -> +2;
                case LAZY -> +1;
                case FLIRTY -> +1; // They liked being tied, so meh about freedom
                default -> +4;
            };

            // MASO trait: less happy about being freed
            if (trait.enjoysBondage()) {
                moodChange = Math.max(0, moodChange - 3);
            }
        }

        modifyMood(entity, moodChange);

        TiedUpMod.LOGGER.debug(
            "[MCA Mood] {} freed: mood +{}",
            entity.getName().getString(),
            moodChange
        );
    }

    /**
     * Called when collar is put on.
     * Generally negative (loss of freedom), but personality-dependent.
     */
    public void onCollared(LivingEntity entity) {
        if (!MCACompat.isMCAVillager(entity)) return;

        MCAPersonality personality =
            MCAPersonalityManager.getInstance().getPersonality(entity);
        TiedUpTrait trait = MCAPersonalityManager.getInstance().getTrait(
            entity
        );

        int moodChange;
        if (personality.isUnpredictable()) {
            moodChange = RANDOM.nextInt(13) - 8; // -8 to +4
        } else {
            moodChange = switch (personality) {
                case SENSITIVE -> -8;
                case CONFIDENT -> -6;
                case SHY -> -4;
                case FRIENDLY -> -3;
                case GRUMPY -> -4;
                case LAZY -> -1;
                case FLIRTY -> +1; // Kinky!
                default -> -4;
            };

            // MASO trait bonus
            if (trait.enjoysBondage()) {
                moodChange += 4;
            }
        }

        modifyMood(entity, moodChange);
    }

    /**
     * Called when collar is removed.
     */
    public void onCollarRemoved(LivingEntity entity) {
        if (!MCACompat.isMCAVillager(entity)) return;

        MCAPersonality personality =
            MCAPersonalityManager.getInstance().getPersonality(entity);
        TiedUpTrait trait = MCAPersonalityManager.getInstance().getTrait(
            entity
        );

        int moodChange = trait.enjoysBondage() ? +1 : +3;

        modifyMood(entity, moodChange);
    }

    /**
     * Called when struggle fails.
     */
    public void onStruggleFailed(LivingEntity entity) {
        if (!MCACompat.isMCAVillager(entity)) return;

        MCAPersonality personality =
            MCAPersonalityManager.getInstance().getPersonality(entity);

        int moodChange = personality == MCAPersonality.CONFIDENT ? -2 : -1;
        modifyMood(entity, moodChange);
    }

    /**
     * Called when struggle succeeds.
     */
    public void onStruggleSuccess(LivingEntity entity) {
        if (!MCACompat.isMCAVillager(entity)) return;

        modifyMood(entity, +3);
    }

    /**
     * Called when gagged.
     */
    public void onGagged(LivingEntity entity) {
        if (!MCACompat.isMCAVillager(entity)) return;

        MCAPersonality personality =
            MCAPersonalityManager.getInstance().getPersonality(entity);
        TiedUpTrait trait = MCAPersonalityManager.getInstance().getTrait(
            entity
        );

        int moodChange = trait.enjoysBondage() ? +1 : -2;
        if (personality == MCAPersonality.SENSITIVE) {
            moodChange -= 2;
        }

        modifyMood(entity, moodChange);
    }

    /**
     * Called when blindfolded.
     */
    public void onBlindfolded(LivingEntity entity) {
        if (!MCACompat.isMCAVillager(entity)) return;

        MCAPersonality personality =
            MCAPersonalityManager.getInstance().getPersonality(entity);
        TiedUpTrait trait = MCAPersonalityManager.getInstance().getTrait(
            entity
        );

        int moodChange = trait.enjoysBondage() ? +1 : -2;
        if (
            personality == MCAPersonality.SHY ||
            personality == MCAPersonality.SENSITIVE
        ) {
            moodChange -= 2; // Extra scary for anxious personalities
        }

        modifyMood(entity, moodChange);
    }

    // REFLECTION-BASED MOOD ACCESS

    /**
     * Modify mood using MCA's modifyMoodValue method via reflection.
     */
    public void modifyMood(LivingEntity entity, int amount) {
        if (amount == 0) return;

        try {
            initializeReflection(entity);

            if (modifyMoodMethod == null) {
                return;
            }

            Object brain = entity
                .getClass()
                .getMethod("getVillagerBrain")
                .invoke(entity);
            if (brain != null) {
                modifyMoodMethod.invoke(brain, amount);
            }
        } catch (Exception e) {
            TiedUpMod.LOGGER.debug(
                "[MCA Mood] Failed to modify mood: {}",
                e.getMessage()
            );
        }
    }

    /**
     * Get current mood value.
     *
     * @return Mood value (typically -15 to 15), or 0 if not available
     */
    public int getMoodValue(LivingEntity entity) {
        try {
            initializeReflection(entity);

            if (getMoodValueMethod == null) {
                return 0;
            }

            Object brain = entity
                .getClass()
                .getMethod("getVillagerBrain")
                .invoke(entity);
            if (brain != null) {
                return (int) getMoodValueMethod.invoke(brain);
            }
        } catch (Exception e) {
            TiedUpMod.LOGGER.debug(
                "[MCAMoodManager] Failed to get mood value via reflection",
                e
            );
        }
        return 0;
    }

    private void initializeReflection(LivingEntity entity) {
        if (reflectionInitialized) return;
        reflectionInitialized = true;

        try {
            Object brain = entity
                .getClass()
                .getMethod("getVillagerBrain")
                .invoke(entity);
            if (brain != null) {
                for (Method m : brain.getClass().getMethods()) {
                    if (
                        m.getName().equals("modifyMoodValue") &&
                        m.getParameterCount() == 1
                    ) {
                        modifyMoodMethod = m;
                    }
                    if (
                        m.getName().equals("getMoodValue") &&
                        m.getParameterCount() == 0
                    ) {
                        getMoodValueMethod = m;
                    }
                }

                if (modifyMoodMethod != null) {
                    TiedUpMod.LOGGER.debug(
                        "[MCA Mood] Found mood methods via reflection"
                    );
                }
            }
        } catch (Exception e) {
            TiedUpMod.LOGGER.debug(
                "[MCA Mood] Reflection init failed: {}",
                e.getMessage()
            );
        }
    }
}
