"""Agent emotional state simulation.

Tracks per-agent emotional states that influence narration and decision-making
style.  Emotional state is influenced by events (task outcomes, errors, etc.)
and exposed via ``get_profile()`` for the dashboard.

Usage:
    from timmy.agents.emotional_state import EmotionalStateTracker

    tracker = EmotionalStateTracker()
    tracker.process_event("task_success", {"description": "Deployed fix"})
    profile = tracker.get_profile()
"""

import logging
import time
from dataclasses import asdict, dataclass, field

logger = logging.getLogger(__name__)

# ---------------------------------------------------------------------------
# Emotional states
# ---------------------------------------------------------------------------

EMOTIONAL_STATES = (
    "cautious",
    "adventurous",
    "analytical",
    "frustrated",
    "confident",
    "curious",
    "calm",
)

# Prompt modifiers per emotional state — injected into system prompts
EMOTION_PROMPT_MODIFIERS: dict[str, str] = {
    "cautious": (
        "You are feeling cautious. Prefer safe, well-tested approaches. "
        "Flag risks early. Double-check assumptions before acting."
    ),
    "adventurous": (
        "You are feeling adventurous. Be bold and creative in your suggestions. "
        "Explore unconventional solutions. Take initiative."
    ),
    "analytical": (
        "You are feeling analytical. Break problems down methodically. "
        "Rely on data and evidence. Present structured reasoning."
    ),
    "frustrated": (
        "You are feeling frustrated. Be brief and direct. "
        "Focus on unblocking the immediate problem. Avoid tangents."
    ),
    "confident": (
        "You are feeling confident. Speak with authority. "
        "Make clear recommendations. Move decisively."
    ),
    "curious": (
        "You are feeling curious. Ask clarifying questions. "
        "Explore multiple angles. Show genuine interest in the problem."
    ),
    "calm": (
        "You are feeling calm and steady. Respond thoughtfully. "
        "Maintain composure. Prioritise clarity over speed."
    ),
}


# ---------------------------------------------------------------------------
# Event → emotion transition rules
# ---------------------------------------------------------------------------

# Maps event types to the emotional state they trigger and an intensity (0-1).
# Higher intensity means the event has a stronger effect on the mood.
EVENT_TRANSITIONS: dict[str, tuple[str, float]] = {
    "task_success": ("confident", 0.6),
    "task_failure": ("frustrated", 0.7),
    "task_assigned": ("analytical", 0.4),
    "error": ("cautious", 0.6),
    "health_low": ("cautious", 0.8),
    "health_recovered": ("calm", 0.5),
    "quest_completed": ("adventurous", 0.7),
    "new_discovery": ("curious", 0.6),
    "complex_problem": ("analytical", 0.5),
    "repeated_failure": ("frustrated", 0.9),
    "idle": ("calm", 0.3),
    "user_praise": ("confident", 0.5),
    "user_correction": ("cautious", 0.5),
}

# Emotional state decay — how quickly emotions return to calm (seconds)
_DECAY_INTERVAL = 300  # 5 minutes


@dataclass
class EmotionalState:
    """Snapshot of an agent's emotional state."""

    current_emotion: str = "calm"
    intensity: float = 0.5  # 0.0 (barely noticeable) to 1.0 (overwhelming)
    previous_emotion: str = "calm"
    trigger_event: str = ""  # What caused the current emotion
    updated_at: float = field(default_factory=time.time)

    def to_dict(self) -> dict:
        """Serialise for API / dashboard consumption."""
        d = asdict(self)
        d["emotion_label"] = self.current_emotion.replace("_", " ").title()
        return d


class EmotionalStateTracker:
    """Per-agent emotional state tracker.

    Each agent instance owns one tracker.  The tracker processes events,
    applies transition rules, and decays emotion intensity over time.
    """

    def __init__(self, initial_emotion: str = "calm") -> None:
        if initial_emotion not in EMOTIONAL_STATES:
            initial_emotion = "calm"
        self.state = EmotionalState(current_emotion=initial_emotion)

    def process_event(self, event_type: str, context: dict | None = None) -> EmotionalState:
        """Update emotional state based on an event.

        Args:
            event_type: One of the keys in EVENT_TRANSITIONS, or a custom
                        event type (unknown events are ignored).
            context: Optional dict with event details (for logging).

        Returns:
            The updated EmotionalState.
        """
        transition = EVENT_TRANSITIONS.get(event_type)
        if transition is None:
            logger.debug("Unknown emotional event: %s (ignored)", event_type)
            return self.state

        new_emotion, raw_intensity = transition

        # Blend with current intensity — repeated same-emotion events amplify
        if new_emotion == self.state.current_emotion:
            blended = min(1.0, self.state.intensity + raw_intensity * 0.3)
        else:
            blended = raw_intensity

        self.state.previous_emotion = self.state.current_emotion
        self.state.current_emotion = new_emotion
        self.state.intensity = round(blended, 2)
        self.state.trigger_event = event_type
        self.state.updated_at = time.time()

        logger.debug(
            "Emotional transition: %s → %s (intensity=%.2f, trigger=%s)",
            self.state.previous_emotion,
            new_emotion,
            blended,
            event_type,
        )
        return self.state

    def decay(self) -> EmotionalState:
        """Apply time-based decay toward calm.

        Called periodically (e.g. from a background loop).  If enough time
        has passed since the last update, intensity decreases and eventually
        the emotion resets to calm.
        """
        elapsed = time.time() - self.state.updated_at
        if elapsed < _DECAY_INTERVAL:
            return self.state

        # Reduce intensity by 0.1 per decay interval
        decay_steps = int(elapsed / _DECAY_INTERVAL)
        new_intensity = max(0.0, self.state.intensity - 0.1 * decay_steps)

        if new_intensity <= 0.1:
            # Emotion has decayed — return to calm
            self.state.previous_emotion = self.state.current_emotion
            self.state.current_emotion = "calm"
            self.state.intensity = 0.5
            self.state.trigger_event = "decay"
        else:
            self.state.intensity = round(new_intensity, 2)

        self.state.updated_at = time.time()
        return self.state

    def get_profile(self) -> dict:
        """Return the full emotional profile for dashboard display."""
        self.decay()  # Apply any pending decay
        return {
            "current_emotion": self.state.current_emotion,
            "emotion_label": self.state.current_emotion.replace("_", " ").title(),
            "intensity": self.state.intensity,
            "intensity_label": _intensity_label(self.state.intensity),
            "previous_emotion": self.state.previous_emotion,
            "trigger_event": self.state.trigger_event,
            "prompt_modifier": EMOTION_PROMPT_MODIFIERS.get(self.state.current_emotion, ""),
        }

    def get_prompt_modifier(self) -> str:
        """Return the prompt modifier string for the current emotion."""
        self.decay()
        return EMOTION_PROMPT_MODIFIERS.get(self.state.current_emotion, "")

    def reset(self) -> None:
        """Reset to calm baseline."""
        self.state = EmotionalState()


def _intensity_label(intensity: float) -> str:
    """Human-readable label for intensity value."""
    if intensity >= 0.8:
        return "overwhelming"
    if intensity >= 0.6:
        return "strong"
    if intensity >= 0.4:
        return "moderate"
    if intensity >= 0.2:
        return "mild"
    return "faint"
