"""
Cognitive Router - Orchestrates System 1 (Fast) and System 2 (Slow) thinking.
"""

import time
from typing import Dict, Any, Tuple, Optional
from loguru import logger

from .engine import HAIMEngine
from .binary_hdv import majority_bundle, BinaryHDV
from .exceptions import MnemoCoreError


class CognitiveRouter:
    """
    Orchestrates System 1 (Fast) and System 2 (Slow) thinking.

    System 1: Intuitive, heuristic, fast memory retrieval.
    System 2: Analytical, epistemic search, heavy reasoning.
    """

    def __init__(self, engine: HAIMEngine):
        self.engine = engine
        self.complexity_threshold = 0.6  # Threshold for switching to Sys2

    async def route(self, impulse: str, context: dict = None) -> Tuple[str, Dict[str, Any]]:
        """
        Route the impulse to the appropriate system.
        Returns: (response, debug_info)
        """
        start_time = time.time()
        complexity = await self._assess_complexity(impulse)

        debug_info = {
            "impulse": impulse,
            "complexity_score": complexity,
            "timestamp": start_time
        }

        if complexity < self.complexity_threshold:
            # System 1: Fast Reflex
            debug_info["system"] = "Sys1 (Fast)"
            response = await self._system_1_reflex(impulse)
        else:
            # System 2: Heavy Reasoning
            debug_info["system"] = "Sys2 (Slow)"
            response = await self._system_2_reasoning(impulse, context)

        debug_info["duration"] = time.time() - start_time
        return response, debug_info

    async def _assess_complexity(self, text: str) -> float:
        """
        Heuristic to estimate cognitive load.
        """
        score = 0.0

        # Length heuristic
        if len(text.split()) > 20:
            score += 0.3

        # Complexity markers
        complex_markers = ["analyze", "compare", "why", "how", "plan", "design", "evaluate"]
        if any(marker in text.lower() for marker in complex_markers):
            score += 0.4

        # Uncertainty markers
        uncertainty = ["maybe", "unsure", "unknown", "complex"]
        if any(u in text.lower() for u in uncertainty):
            score += 0.2

        # Epistemic check (query engine for familiarity)
        # Low familiarity (high surprise) -> Higher complexity
        try:
            results = await self.engine.query(text, top_k=1, associative_jump=False)
            if results and results[0][1] > 0.8:
                # Strong memory match -> Familiar -> Lower complexity
                score -= 0.3
            elif not results or results[0][1] < 0.3:
                # No clue -> Novelty -> Higher complexity
                score += 0.4
        except MnemoCoreError as e:
            # Log domain errors but continue with heuristic-only assessment
            logger.debug(f"Complexity assessment query failed: {e}")
        except Exception as e:
            # Log unexpected errors but continue
            logger.warning(f"Unexpected error in complexity assessment: {e}")

        return min(1.0, max(0.0, score))

    async def _system_1_reflex(self, impulse: str) -> str:
        """
        Fast retrieval and simple association.
        """
        # 1. Quick memory lookup
        results = await self.engine.query(impulse, top_k=3)

        if not results:
            return "I don't have an immediate reflex for that."

        # 2. Synthesize simple answer from top memory (simulated)
        # Use engine.get_memory() instead of direct dict access
        top_mem_id, score = results[0]
        node = await self.engine.get_memory(top_mem_id)

        content = node.content if node else 'Unknown'
        return f"[Reflex] Based on memory ({score:.2f}): {content}"

    async def _system_2_reasoning(self, impulse: str, context: Optional[dict]) -> str:
        """Slow, deliberative process with Epistemic Drive."""
        eig: Optional[float] = None

        # 1. Epistemic Drive (Expected Information Gain)
        if self.engine.epistemic_drive_active:
            candidate_vec = self.engine.encode_content(impulse)

            # Build context vector from working memory or sample from engine
            ctx_vec: BinaryHDV

            if context and isinstance(context.get("working_memory"), list) and context["working_memory"]:
                vectors = []
                for item in context["working_memory"]:
                    vectors.append(self.engine.encode_content(str(item)))

                # Bundle all context vectors
                if vectors:
                    ctx_vec = majority_bundle(vectors)
                else:
                    ctx_vec = await self.engine._current_context_vector()
            else:
                ctx_vec = await self.engine._current_context_vector(sample_n=50)

            eig = self.engine.calculate_eig(candidate_vec, ctx_vec)

        # 2. Deep Search (Associative Jumps)
        results = await self.engine.query(impulse, top_k=10, associative_jump=True)

        # 3. Consolidation / Synthesis
        memories = []
        for mid, score in results:
            node = await self.engine.get_memory(mid)
            if node:
                memories.append(f"- {node.content} (conf: {score:.2f})")

        knowledge_block = "\n".join(memories)

        eig_line = f"\nEpistemic Drive (EIG): {eig:.2f}" if eig is not None else ""
        return f"[Reasoning] I have analyzed {len(memories)} data points.{eig_line}\nKey insights:\n{knowledge_block}"
