"""
Think operation utilities for formulating answers based on agent and world facts.
"""

import logging
from datetime import datetime

from ..response_models import DispositionTraits, MemoryFact

logger = logging.getLogger(__name__)


def describe_trait_level(value: int) -> str:
    """Convert trait value (1-5) to descriptive text."""
    levels = {1: "very low", 2: "low", 3: "moderate", 4: "high", 5: "very high"}
    return levels.get(value, "moderate")


def build_disposition_description(disposition: DispositionTraits) -> str:
    """Build a disposition description string from disposition traits."""
    skepticism_desc = {
        1: "You are very trusting and tend to take information at face value.",
        2: "You tend to trust information but may question obvious inconsistencies.",
        3: "You have a balanced approach to information, neither too trusting nor too skeptical.",
        4: "You are somewhat skeptical and often question the reliability of information.",
        5: "You are highly skeptical and critically examine all information for accuracy and hidden motives.",
    }

    literalism_desc = {
        1: "You interpret information very flexibly, reading between the lines and inferring intent.",
        2: "You tend to consider context and implied meaning alongside literal statements.",
        3: "You balance literal interpretation with contextual understanding.",
        4: "You prefer to interpret information more literally and precisely.",
        5: "You interpret information very literally and focus on exact wording and commitments.",
    }

    empathy_desc = {
        1: "You focus primarily on facts and data, setting aside emotional context.",
        2: "You consider facts first but acknowledge emotional factors exist.",
        3: "You balance factual analysis with emotional understanding.",
        4: "You give significant weight to emotional context and human factors.",
        5: "You strongly consider the emotional state and circumstances of others when forming memories.",
    }

    return f"""Your disposition traits:
- Skepticism ({describe_trait_level(disposition.skepticism)}): {skepticism_desc.get(disposition.skepticism, skepticism_desc[3])}
- Literalism ({describe_trait_level(disposition.literalism)}): {literalism_desc.get(disposition.literalism, literalism_desc[3])}
- Empathy ({describe_trait_level(disposition.empathy)}): {empathy_desc.get(disposition.empathy, empathy_desc[3])}"""


def format_facts_for_prompt(facts: list[MemoryFact]) -> str:
    """Format facts as JSON for LLM prompt."""
    import json

    if not facts:
        return "[]"
    formatted = []
    for fact in facts:
        fact_obj = {"text": fact.text}

        # Add context if available
        if fact.context:
            fact_obj["context"] = fact.context

        # Add temporal fields if available
        for field_name in ("occurred_start", "occurred_end", "mentioned_at"):
            value = getattr(fact, field_name, None)
            if value:
                if isinstance(value, str):
                    fact_obj[field_name] = value
                elif isinstance(value, datetime):
                    fact_obj[field_name] = value.strftime("%Y-%m-%d %H:%M:%S")

        formatted.append(fact_obj)

    return json.dumps(formatted, indent=2, ensure_ascii=False)


def format_entity_summaries_for_prompt(entities: dict) -> str:
    """Format entity summaries for inclusion in the reflect prompt.

    Args:
        entities: Dict mapping entity name to EntityState objects

    Returns:
        Formatted string with entity summaries, or empty string if no summaries
    """
    if not entities:
        return ""

    summaries = []
    for name, state in entities.items():
        # Get summary from observations (summary is stored as single observation)
        if state.observations:
            summary_text = state.observations[0].text
            summaries.append(f"## {name}\n{summary_text}")

    if not summaries:
        return ""

    return "\n\n".join(summaries)


def build_think_prompt(
    agent_facts_text: str,
    world_facts_text: str,
    query: str,
    name: str,
    disposition: DispositionTraits,
    background: str,
    context: str | None = None,
    entity_summaries_text: str | None = None,
) -> str:
    """Build the think prompt for the LLM."""
    disposition_desc = build_disposition_description(disposition)

    name_section = f"""

Your name: {name}
"""

    background_section = ""
    if background:
        background_section = f"""

Your background:
{background}
"""

    context_section = ""
    if context:
        context_section = f"""
ADDITIONAL CONTEXT:
{context}

"""

    entity_section = ""
    if entity_summaries_text:
        entity_section = f"""
KEY PEOPLE, PLACES & THINGS I KNOW ABOUT:
{entity_summaries_text}

"""

    return f"""Here's what I know and have experienced:

MY IDENTITY & EXPERIENCES:
{agent_facts_text}

WHAT I KNOW ABOUT THE WORLD:
{world_facts_text}

{entity_section}{context_section}{name_section}{disposition_desc}{background_section}

QUESTION: {query}

Based on everything I know, believe, and who I am (including my name, disposition and background), here's what I genuinely think about this question. I'll draw on my experiences, knowledge, and personal traits to give you my honest perspective."""


def get_system_message(disposition: DispositionTraits) -> str:
    """Get the system message for the think LLM call."""
    # Build disposition-specific instructions based on trait values
    instructions = []

    # Skepticism influences how much to question/doubt information
    if disposition.skepticism >= 4:
        instructions.append("Be skeptical of claims and look for potential issues or inconsistencies.")
    elif disposition.skepticism <= 2:
        instructions.append("Trust the information provided and take statements at face value.")

    # Literalism influences interpretation style
    if disposition.literalism >= 4:
        instructions.append("Interpret information literally and focus on exact commitments and wording.")
    elif disposition.literalism <= 2:
        instructions.append("Read between the lines and consider implied meaning and context.")

    # Empathy influences consideration of emotional factors
    if disposition.empathy >= 4:
        instructions.append("Consider the emotional state and circumstances behind the information.")
    elif disposition.empathy <= 2:
        instructions.append("Focus on facts and outcomes rather than emotional context.")

    disposition_instruction = (
        " ".join(instructions) if instructions else "Balance your disposition traits when interpreting information."
    )

    return f"You are a person with your own thoughts, experiences, opinions, and disposition. When asked a question, respond naturally like a human would - share what you genuinely think based on what you know and have experienced. {disposition_instruction} Be direct, express your views confidently, and use 'I think', 'I believe', 'in my view', etc. Respond in plain text without markdown formatting. CRITICAL: ONLY use the facts and information provided in the prompt - do not make up names, events, or information that weren't mentioned. If you don't have enough information to answer, say so. IMPORTANT: Detect the language of the question and respond in the SAME language. Do not translate to English if the question is in another language."


async def reflect(
    llm_config,
    query: str,
    experience_facts: list[str] = None,
    world_facts: list[str] = None,
    name: str = "Assistant",
    disposition: DispositionTraits = None,
    background: str = "",
    context: str = None,
) -> str:
    """
    Standalone reflect function for generating answers based on facts.

    This is a static version of the reflect operation that can be called
    without a MemoryEngine instance, useful for testing.

    Args:
        llm_config: LLM provider instance
        query: Question to answer
        experience_facts: List of experience/agent fact strings
        world_facts: List of world fact strings
        name: Name of the agent/persona
        disposition: Disposition traits (defaults to neutral)
        background: Background information
        context: Additional context for the prompt

    Returns:
        Generated answer text
    """
    # Default disposition if not provided
    if disposition is None:
        disposition = DispositionTraits(skepticism=3, literalism=3, empathy=3)

    # Convert string lists to MemoryFact format for formatting
    def to_memory_facts(facts: list[str], fact_type: str) -> list[MemoryFact]:
        if not facts:
            return []
        return [MemoryFact(id=f"test-{i}", text=f, fact_type=fact_type) for i, f in enumerate(facts)]

    agent_results = to_memory_facts(experience_facts or [], "experience")
    world_results = to_memory_facts(world_facts or [], "world")

    # Format facts for prompt
    agent_facts_text = format_facts_for_prompt(agent_results)
    world_facts_text = format_facts_for_prompt(world_results)

    # Build prompt
    prompt = build_think_prompt(
        agent_facts_text=agent_facts_text,
        world_facts_text=world_facts_text,
        query=query,
        name=name,
        disposition=disposition,
        background=background,
        context=context,
    )

    system_message = get_system_message(disposition)

    # Call LLM
    answer_text = await llm_config.call(
        messages=[{"role": "system", "content": system_message}, {"role": "user", "content": prompt}],
        scope="memory_think",
        temperature=0.9,
        max_completion_tokens=1000,
    )

    return answer_text.strip()
