//! NPC behavior via bhava, bodh, mastishk, and jantu
//!
//! Bridges the AGNOS behavior stack with kiran's ECS:
//! - **bhava** — Personality traits and emotional state
//! - **bodh** — Psychology (cognition, perception, learning, decision-making)
//! - **mastishk** — Computational neuroscience (neurotransmitters, sleep, HPA axis)
//! - **jantu** — Ethology (instincts, survival, social dynamics, swarm intelligence)
//!
//! Core types:
//! - [`Personality`] component wrapping bhava PersonalityProfile + MoodVector
//! - [`Cognition`] component for perception, memory, and decision-making
//! - [`NeuralState`] component for neuroscience-driven behavior
//! - [`CreatureBehavior`] component for instinct-driven creatures
//! - Mood stimulus system for event-driven emotion changes

use crate::world::{Entity, EventBus, World};

// ---------------------------------------------------------------------------
// bodh — psychology
// ---------------------------------------------------------------------------

/// Attention (Posner cueing, attentional blink).
pub use bodh::attention;
/// Bayesian reasoning (belief updating, base rate neglect).
pub use bodh::bayesian;
/// Cognitive processes (working memory, dual-process theory).
pub use bodh::cognition as bodh_cognition;
/// Decision-making (prospect theory, bounded rationality).
pub use bodh::decision;
/// Emotion models (Russell circumplex, appraisal, regulation).
pub use bodh::emotion as bodh_emotion;
/// Learning models (Ebbinghaus forgetting curve, conditioning).
pub use bodh::learning;
/// Memory models (ACT-R activation, spreading activation).
pub use bodh::memory;
/// Motivation (self-determination theory, flow state).
pub use bodh::motivation;
/// Perception (signal detection theory).
pub use bodh::perception;
/// Psychophysics (Weber-Fechner law, Fitts' law, Hick's law).
pub use bodh::psychophysics;
/// Social psychology (conformity, attribution, social impact).
pub use bodh::social;
/// Stress models (transactional stress, coping).
pub use bodh::stress;

// ---------------------------------------------------------------------------
// mastishk — computational neuroscience
// ---------------------------------------------------------------------------

/// Autonomic nervous system (sympathetic/parasympathetic, HRV).
pub use mastishk::autonomic;
/// Brain state integration (central tick, age profiles, interoception).
pub use mastishk::brain;
/// Bridge types for downstream consumers.
pub use mastishk::bridge as neuro_bridge;
/// Chronobiology (circadian pacemaker, melatonin, cortisol awakening).
pub use mastishk::chronobiology;
/// Neural circuit models (rate populations, Hebbian plasticity).
pub use mastishk::circuit;
/// Cross-module coupling functions.
pub use mastishk::coupling;
/// HPA axis (CRH → ACTH → cortisol cascade, allostatic load).
pub use mastishk::hpa;
/// Neurotransmitter dynamics (dopamine, serotonin, norepinephrine, etc.).
pub use mastishk::neurotransmitter;
/// Receptor subtypes and desensitization.
pub use mastishk::receptor;
/// Brain region models (PFC, amygdala, hippocampus, basal ganglia).
pub use mastishk::regions;
/// Sleep models (Borbely two-process, ultradian cycles).
pub use mastishk::sleep;

// ---------------------------------------------------------------------------
// jantu — ethology / creature behavior
// ---------------------------------------------------------------------------

/// Foraging strategies (optimal foraging, prey selection).
pub use jantu::foraging;
/// Habituation and sensitization.
pub use jantu::habituation;
/// Core instinct system (drives, priority weights).
pub use jantu::instinct;
/// Migration patterns.
pub use jantu::migration;
/// Pack behavior (hunting, food sharing).
pub use jantu::pack;
/// Signal communication (alarm calls, displays).
pub use jantu::signals;
/// Social dynamics (hierarchy, roles, group cohesion).
pub use jantu::social as jantu_social;
/// Survival state and threat response.
pub use jantu::survival;
/// Swarm intelligence (pheromone trails, quorum sensing).
pub use jantu::swarm;
/// Territory marking and defense.
pub use jantu::territory;

/// NPC personality and emotional state component.
pub struct Personality {
    /// Trait profile (formality, warmth, curiosity, patience, etc.)
    pub profile: bhava::traits::PersonalityProfile,
    /// Current emotional state.
    pub mood: bhava::mood::MoodVector,
    /// Whether this NPC is actively processing stimuli.
    pub active: bool,
}

impl Personality {
    /// Create a new personality with a name and neutral mood.
    pub fn new(name: impl Into<String>) -> Self {
        Self {
            profile: bhava::traits::PersonalityProfile::new(name),
            mood: bhava::mood::MoodVector::neutral(),
            active: true,
        }
    }

    /// Set a personality trait.
    pub fn set_trait(&mut self, kind: bhava::traits::TraitKind, level: bhava::traits::TraitLevel) {
        self.profile.set_trait(kind, level);
    }

    /// Get the dominant emotion.
    #[must_use]
    pub fn dominant_emotion(&self) -> bhava::mood::Emotion {
        self.mood.dominant_emotion()
    }

    /// Apply a mood stimulus (nudge an emotion). Intensity is clamped to [-1.0, 1.0].
    pub fn stimulate(&mut self, emotion: bhava::mood::Emotion, intensity: f32) {
        self.mood.nudge(emotion, intensity.clamp(-1.0, 1.0));
    }

    /// Decay mood toward neutral over time.
    pub fn decay_mood(&mut self, factor: f32) {
        self.mood.decay(factor);
    }

    /// Get the emotional intensity (how far from neutral).
    #[must_use]
    #[inline]
    pub fn emotional_intensity(&self) -> f32 {
        self.mood.intensity()
    }

    /// Generate a behavioral prompt string for AI (combines personality + mood).
    #[must_use]
    pub fn compose_prompt(&self) -> String {
        use std::fmt::Write;
        let personality_prompt = self.profile.compose_prompt();
        let dominant = self.dominant_emotion();
        let intensity = self.emotional_intensity();
        let mut out = personality_prompt;
        let _ = write!(
            out,
            "\nCurrent mood: {dominant:?} (intensity: {intensity:.2})"
        );
        out
    }
}

// ---------------------------------------------------------------------------
// Mood stimulus event
// ---------------------------------------------------------------------------

/// Event that stimulates an NPC's mood.
#[derive(Debug, Clone)]
pub struct MoodStimulus {
    /// Target NPC entity.
    pub entity: Entity,
    /// Emotion to stimulate.
    pub emotion: bhava::mood::Emotion,
    /// Stimulus strength (clamped to [-1.0, 1.0]).
    pub intensity: f32,
}

/// Process mood stimulus events from the event bus.
pub fn process_mood_stimuli(world: &mut World) {
    let stimuli = {
        let Some(bus) = world.get_resource_mut::<EventBus>() else {
            return;
        };
        bus.drain::<MoodStimulus>()
    };

    for stimulus in stimuli {
        if let Some(personality) = world.get_component_mut::<Personality>(stimulus.entity)
            && personality.active
        {
            personality.stimulate(stimulus.emotion, stimulus.intensity);
        }
    }
}

/// Decay all NPC moods toward neutral. Call once per frame.
pub fn decay_all_moods(world: &mut World, factor: f32) {
    let entities: Vec<Entity> = world
        .query::<Personality>()
        .iter()
        .filter(|(_, p)| p.active)
        .map(|(e, _)| *e)
        .collect();

    for entity in entities {
        if let Some(personality) = world.get_component_mut::<Personality>(entity) {
            personality.decay_mood(factor);
        }
    }
}

// ---------------------------------------------------------------------------
// Cognition component (bodh)
// ---------------------------------------------------------------------------

/// Cognitive state for an NPC — perception, memory saliency, and decision confidence.
///
/// Wraps bodh's psychology functions into per-entity state that systems can
/// query and update each frame.
#[derive(Debug, Clone)]
pub struct Cognition {
    /// Working memory load (0.0 = free, 1.0 = saturated).
    pub memory_load: f32,
    /// Attention focus level (0.0 = distracted, 1.0 = fully focused).
    pub attention: f32,
    /// Current stress level (0.0 = calm, 1.0 = overwhelmed).
    pub stress: f32,
    /// Learning rate modifier (higher = faster skill acquisition).
    pub learning_rate: f32,
    /// Whether this NPC is actively processing cognitive tasks.
    pub active: bool,
}

impl Cognition {
    /// Create a new cognition component with neutral defaults.
    ///
    /// # Examples
    ///
    /// ```
    /// # #[cfg(feature = "behavior")] {
    /// use kiran::personality::Cognition;
    ///
    /// let cog = Cognition::new();
    /// assert_eq!(cog.attention, 1.0);
    /// assert_eq!(cog.stress, 0.0);
    /// # }
    /// ```
    pub fn new() -> Self {
        Self {
            memory_load: 0.0,
            attention: 1.0,
            stress: 0.0,
            learning_rate: 1.0,
            active: true,
        }
    }

    /// Apply Hick's law: decision time increases with number of choices.
    /// The `b` parameter scales the log term (typical ~0.155 seconds).
    #[must_use]
    #[inline]
    pub fn decision_time(&self, num_choices: usize, b: f64) -> Option<f64> {
        psychophysics::hicks_law(num_choices, b).ok()
    }

    /// Apply Fitts' law: movement time for a target at given distance and width.
    #[must_use]
    #[inline]
    pub fn movement_time(&self, distance: f64, width: f64) -> Option<f64> {
        psychophysics::fitts_law(distance, width).ok()
    }

    /// Apply Ebbinghaus forgetting: retention after elapsed time with given stability.
    #[must_use]
    #[inline]
    pub fn retention(&self, elapsed_hours: f64, stability: f64) -> Option<f64> {
        learning::ebbinghaus_forgetting(elapsed_hours, stability).ok()
    }
}

impl Default for Cognition {
    fn default() -> Self {
        Self::new()
    }
}

// ---------------------------------------------------------------------------
// Neural state component (mastishk)
// ---------------------------------------------------------------------------

/// Neuroscience-driven brain state for an NPC.
///
/// Wraps mastishk's `BrainState` for tick-based neural simulation.
/// The brain state drives neurotransmitter levels, sleep pressure,
/// cortisol response, and autonomic tone — which feed back into
/// mood and behavior via the bridge output.
pub struct NeuralState {
    /// The underlying mastishk brain state.
    pub brain: brain::BrainState,
    /// Whether this neural simulation is active.
    pub active: bool,
}

impl NeuralState {
    /// Create a new neural state.
    pub fn new() -> Self {
        Self {
            brain: brain::BrainState::default(),
            active: true,
        }
    }
}

impl Default for NeuralState {
    fn default() -> Self {
        Self::new()
    }
}

// ---------------------------------------------------------------------------
// Creature behavior component (jantu)
// ---------------------------------------------------------------------------

/// Instinct-driven behavior state for a creature entity.
///
/// Wraps jantu's instinct system for drive-based creature AI.
/// Each creature has a set of drives (hunger, thirst, fear, mating, etc.)
/// that compete for behavioral priority.
#[derive(Debug, Clone)]
pub struct CreatureBehavior {
    /// The creature's instinct state (drives and priority weights).
    pub instincts: instinct::Instinct,
    /// Current survival state.
    pub survival: survival::SurvivalState,
    /// Social hierarchy position.
    pub hierarchy: jantu_social::HierarchyPosition,
    /// Whether this creature is actively processing behavior.
    pub active: bool,
}

impl CreatureBehavior {
    /// Create a new creature behavior with the given instinct type.
    ///
    /// # Examples
    ///
    /// ```
    /// # #[cfg(feature = "behavior")] {
    /// use kiran::personality::CreatureBehavior;
    /// use kiran::personality::instinct::InstinctType;
    ///
    /// let behavior = CreatureBehavior::new(InstinctType::Hunger);
    /// assert!(behavior.active);
    /// # }
    /// ```
    pub fn new(instinct_type: instinct::InstinctType) -> Self {
        Self {
            instincts: instinct::Instinct::new(instinct_type),
            survival: survival::SurvivalState::Stable,
            hierarchy: jantu_social::HierarchyPosition::new(0.5),
            active: true,
        }
    }
}

impl Default for CreatureBehavior {
    fn default() -> Self {
        Self::new(instinct::InstinctType::Curiosity)
    }
}

// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------

#[cfg(test)]
mod tests {
    use super::*;
    use bhava::mood::Emotion;
    use bhava::traits::{TraitKind, TraitLevel};

    #[test]
    fn personality_new() {
        let p = Personality::new("Guard");
        assert!(p.active);
        assert!((p.emotional_intensity()).abs() < 0.01);
    }

    #[test]
    fn personality_set_trait() {
        let mut p = Personality::new("Merchant");
        p.set_trait(TraitKind::Curiosity, TraitLevel::High);
        let level = p.profile.get_trait(TraitKind::Curiosity);
        assert_eq!(level, TraitLevel::High);
    }

    #[test]
    fn personality_stimulate() {
        let mut p = Personality::new("Villager");
        p.stimulate(Emotion::Joy, 0.8);
        assert!(p.emotional_intensity() > 0.0);
        assert_eq!(p.dominant_emotion(), Emotion::Joy);
    }

    #[test]
    fn personality_decay() {
        let mut p = Personality::new("Soldier");
        p.stimulate(Emotion::Frustration, 1.0);
        let before = p.emotional_intensity();
        p.decay_mood(0.5);
        assert!(p.emotional_intensity() < before);
    }

    #[test]
    fn personality_compose_prompt() {
        let mut p = Personality::new("Innkeeper");
        p.set_trait(TraitKind::Warmth, TraitLevel::Highest);
        p.stimulate(Emotion::Joy, 0.5);
        let prompt = p.compose_prompt();
        assert!(prompt.contains("Joy"));
    }

    #[test]
    fn personality_as_component() {
        let mut world = World::new();
        let e = world.spawn();
        world.insert_component(e, Personality::new("NPC")).unwrap();
        assert!(world.has_component::<Personality>(e));
    }

    #[test]
    fn mood_stimulus_system() {
        let mut world = World::new();
        world.insert_resource(EventBus::new());

        let npc = world.spawn();
        world
            .insert_component(npc, Personality::new("Guard"))
            .unwrap();

        // Publish stimulus
        {
            let bus = world.get_resource_mut::<EventBus>().unwrap();
            bus.publish(MoodStimulus {
                entity: npc,
                emotion: Emotion::Arousal,
                intensity: 0.7,
            });
        }

        process_mood_stimuli(&mut world);

        let p = world.get_component::<Personality>(npc).unwrap();
        assert!(p.mood.get(Emotion::Arousal) > 0.0);
    }

    #[test]
    fn mood_stimulus_inactive_npc() {
        let mut world = World::new();
        world.insert_resource(EventBus::new());

        let npc = world.spawn();
        let mut personality = Personality::new("Sleeping");
        personality.active = false;
        world.insert_component(npc, personality).unwrap();

        {
            let bus = world.get_resource_mut::<EventBus>().unwrap();
            bus.publish(MoodStimulus {
                entity: npc,
                emotion: Emotion::Frustration,
                intensity: 1.0,
            });
        }

        process_mood_stimuli(&mut world);

        let p = world.get_component::<Personality>(npc).unwrap();
        assert!((p.emotional_intensity()).abs() < 0.01); // unchanged
    }

    #[test]
    fn decay_all_moods_system() {
        let mut world = World::new();

        let npc1 = world.spawn();
        let mut p1 = Personality::new("A");
        p1.stimulate(Emotion::Joy, 1.0);
        world.insert_component(npc1, p1).unwrap();

        let npc2 = world.spawn();
        let mut p2 = Personality::new("B");
        p2.stimulate(Emotion::Trust, 1.0);
        world.insert_component(npc2, p2).unwrap();

        decay_all_moods(&mut world, 0.5);

        let p1 = world.get_component::<Personality>(npc1).unwrap();
        let p2 = world.get_component::<Personality>(npc2).unwrap();
        assert!(p1.mood.get(Emotion::Joy) < 1.0);
        assert!(p2.mood.get(Emotion::Trust) < 1.0);
    }

    #[test]
    fn multiple_stimuli_accumulate() {
        let mut world = World::new();
        world.insert_resource(EventBus::new());

        let npc = world.spawn();
        world
            .insert_component(npc, Personality::new("Target"))
            .unwrap();

        {
            let bus = world.get_resource_mut::<EventBus>().unwrap();
            bus.publish(MoodStimulus {
                entity: npc,
                emotion: Emotion::Joy,
                intensity: 0.3,
            });
            bus.publish(MoodStimulus {
                entity: npc,
                emotion: Emotion::Joy,
                intensity: 0.3,
            });
        }

        process_mood_stimuli(&mut world);

        let p = world.get_component::<Personality>(npc).unwrap();
        assert!(p.mood.get(Emotion::Joy) > 0.5);
    }

    #[test]
    fn compose_prompt_empty_profile() {
        let p = Personality::new("Blank");
        let prompt = p.compose_prompt();
        assert!(!prompt.is_empty());
    }

    #[test]
    fn query_personality_entities() {
        let mut world = World::new();
        let npc1 = world.spawn();
        let npc2 = world.spawn();
        let _non_npc = world.spawn();

        world.insert_component(npc1, Personality::new("A")).unwrap();
        world.insert_component(npc2, Personality::new("B")).unwrap();

        let npcs = world.query::<Personality>();
        assert_eq!(npcs.len(), 2);
    }

    #[test]
    fn personality_multiple_traits() {
        let mut p = Personality::new("Complex");
        p.set_trait(TraitKind::Warmth, TraitLevel::Highest);
        p.set_trait(TraitKind::Humor, TraitLevel::High);
        p.set_trait(TraitKind::Patience, TraitLevel::Low);

        assert_eq!(p.profile.get_trait(TraitKind::Warmth), TraitLevel::Highest);
        assert_eq!(p.profile.get_trait(TraitKind::Humor), TraitLevel::High);
        assert_eq!(p.profile.get_trait(TraitKind::Patience), TraitLevel::Low);
    }

    #[test]
    fn stimulate_clamps_intensity() {
        let mut p = Personality::new("Clamped");
        p.stimulate(Emotion::Joy, 5.0); // over 1.0 → clamped to 1.0
        assert!(p.mood.get(Emotion::Joy) <= 1.0);
    }

    #[test]
    fn mood_blend_multiple_emotions() {
        let mut p = Personality::new("Mixed");
        p.stimulate(Emotion::Joy, 0.5);
        p.stimulate(Emotion::Frustration, 0.8);
        // Frustration is stronger
        assert_eq!(p.dominant_emotion(), Emotion::Frustration);
    }
}
