"""Memory Router — classifies incoming information into memory types.

Uses rule-based heuristics to determine if input is:
- EPISODIC: timestamped events, conversations, "what happened"
- SEMANTIC: facts, relationships, "what is true"
- PROCEDURAL: tools, schemas, code, "how to do"
"""

from __future__ import annotations

import re

from mnemosynth.core.types import MemoryType


# Pattern matchers for each memory type
EPISODIC_PATTERNS = [
    r"\b(yesterday|today|last\s+(?:week|month|year)|ago|session|meeting)\b",
    r"\b(happened|occurred|did|went|said|told|discussed|talked)\b",
    r"\b(remember\s+when|that\s+time|earlier|previously|just\s+now)\b",
    r"\d{4}-\d{2}-\d{2}",  # ISO date
    r"\b(at\s+\d{1,2}:\d{2}|morning|afternoon|evening|night)\b",
]

PROCEDURAL_PATTERNS = [
    r"\b(how\s+to|steps?\s+to|procedure|workflow|recipe|algorithm)\b",
    r"\b(tool|function|method|command|script|api|endpoint)\b",
    r"\b(install|setup|configure|deploy|run|execute|build)\b",
    r"```",  # Code block
    r"\b(def\s+|class\s+|import\s+|from\s+)",  # Python code
    r"\b(npm|pip|cargo|docker|git)\s+",  # CLI tools
]

SEMANTIC_PATTERNS = [
    r"\b(is|are|was|were|has|have|means|refers\s+to)\b",
    r"\b(prefers?|likes?|uses?|works?\s+(?:with|at|on)|lives?\s+in)\b",
    r"\b(always|never|usually|generally|typically)\b",
    r"\b(fact|true|false|correct|wrong|actually)\b",
    r"\b(name\s+is|born\s+in|works?\s+as|specializes?\s+in)\b",
]


class MemoryRouter:
    """Classify incoming text into episodic, semantic, or procedural memory types.

    Uses a scoring-based approach with pattern matching heuristics.
    """

    def classify(self, text: str) -> MemoryType:
        """Classify text into a memory type.

        Returns the most likely MemoryType with a confidence score.
        Falls back to SEMANTIC for ambiguous inputs.
        """
        scores = self._compute_scores(text)

        # Get the highest scoring type
        best_type = max(scores, key=scores.get)  # type: ignore
        return best_type

    def classify_with_confidence(self, text: str) -> tuple[MemoryType, float]:
        """Classify text and return confidence score."""
        scores = self._compute_scores(text)
        best_type = max(scores, key=scores.get)  # type: ignore
        total = sum(scores.values()) or 1.0
        confidence = scores[best_type] / total
        return best_type, confidence

    def _compute_scores(self, text: str) -> dict[MemoryType, float]:
        """Score text against each memory type's patterns."""
        text_lower = text.lower()

        scores = {
            MemoryType.EPISODIC: 0.0,
            MemoryType.SEMANTIC: 0.1,  # Slight default bias toward semantic
            MemoryType.PROCEDURAL: 0.0,
        }

        # Check episodic patterns
        for pattern in EPISODIC_PATTERNS:
            matches = len(re.findall(pattern, text_lower))
            scores[MemoryType.EPISODIC] += matches * 1.0

        # Check procedural patterns
        for pattern in PROCEDURAL_PATTERNS:
            matches = len(re.findall(pattern, text_lower))
            scores[MemoryType.PROCEDURAL] += matches * 1.0

        # Check semantic patterns
        for pattern in SEMANTIC_PATTERNS:
            matches = len(re.findall(pattern, text_lower))
            scores[MemoryType.SEMANTIC] += matches * 1.0

        # Heuristic boosts
        # Long text with timestamps → likely episodic
        if len(text) > 200 and scores[MemoryType.EPISODIC] > 0:
            scores[MemoryType.EPISODIC] *= 1.3

        # Contains code → procedural
        if "```" in text or re.search(r"def\s+\w+", text):
            scores[MemoryType.PROCEDURAL] += 3.0

        # Short factual statement → semantic
        if len(text) < 100 and scores[MemoryType.SEMANTIC] > 0:
            scores[MemoryType.SEMANTIC] *= 1.2

        return scores
