"""Anthropic adapter — wraps Claude messages API with automatic LociDB memory."""

from __future__ import annotations

import re
from typing import Any, Dict, List, Optional

from ..core.db import LociDB


_MEMORY_SYSTEM_TEMPLATE = """You have access to the following relevant memories from previous conversations:

{memories}

Use these memories to provide more contextual and informed responses. If a memory contradicts the current conversation, prefer the current conversation."""


def _format_memories(results: List[Dict]) -> str:
    if not results:
        return "No relevant memories found."
    lines = []
    for i, r in enumerate(results, 1):
        node = r["node"]
        score = r.get("composite_score", r.get("similarity", 0))
        lines.append(f"{i}. [{score:.2f}] {node.content}")
    return "\n".join(lines)


def _extract_entities(text: str) -> List[str]:
    entities: set[str] = set()
    for m in re.finditer(r'"([^"]+)"', text):
        entities.add(m.group(1))
    for m in re.finditer(r"\b([A-Z][a-z]+(?:\s+[A-Z][a-z]+)*)\b", text):
        word = m.group(1)
        if len(word) > 2 and word not in {"The", "This", "That", "What", "How", "Why", "When", "Where"}:
            entities.add(word)
    return list(entities)


class LociAnthropicMemory:
    """Memory layer for the Anthropic Python client.

    Usage::

        import anthropic
        from locidb.adapters import LociAnthropicMemory

        client = anthropic.Anthropic()
        memory = LociAnthropicMemory(db_path="./memory.loci")

        response = memory.chat(
            client=client,
            model="claude-sonnet-4-20250514",
            user_message="How should I optimize Dropzi deliveries?",
            scope="project:dropzi",
        )
    """

    def __init__(
        self,
        db_path: str = "./memory.loci",
        recall_top_k: int = 8,
        min_importance: float = 0.3,
        time_window_days: Optional[int] = 30,
        auto_memorize: bool = True,
    ) -> None:
        self.db = LociDB(path=db_path)
        self.recall_top_k = recall_top_k
        self.min_importance = min_importance
        self.time_window_days = time_window_days
        self.auto_memorize = auto_memorize

    def chat(
        self,
        client: Any,
        model: str = "claude-sonnet-4-20250514",
        user_message: str = "",
        scope: str = "global",
        system_prompt: Optional[str] = None,
        messages: Optional[List[Dict[str, str]]] = None,
        entities: Optional[List[str]] = None,
        max_tokens: int = 1024,
        **kwargs: Any,
    ) -> Any:
        if entities is None:
            entities = _extract_entities(user_message)

        results = self.db.recall(
            query=user_message,
            entities=entities or None,
            scope=scope,
            time_window_days=self.time_window_days,
            min_importance=self.min_importance,
            top_k=self.recall_top_k,
        )

        persona_text = self.db.get_persona_prompt()
        corrections = self.db.get_corrections(scope=scope, limit=5)
        correction_text = ""
        if corrections:
            correction_lines = ["## Corrections (always apply these):"]
            for c in corrections:
                correction_lines.append(f"- {c.content}")
            correction_text = "\n".join(correction_lines)

        memory_text = _format_memories(results)
        memory_system = _MEMORY_SYSTEM_TEMPLATE.format(memories=memory_text)
        base_system = system_prompt or "You are a helpful assistant."

        parts = [base_system]
        if persona_text:
            parts.append(persona_text)
        if correction_text:
            parts.append(correction_text)
        parts.append(memory_system)
        full_system = "\n\n".join(parts)

        if messages is None:
            messages = []
        final_messages = list(messages)
        if user_message:
            final_messages.append({"role": "user", "content": user_message})

        response = client.messages.create(
            model=model,
            max_tokens=max_tokens,
            system=full_system,
            messages=final_messages,
            **kwargs,
        )

        if self.auto_memorize:
            assistant_content = ""
            for block in response.content:
                if hasattr(block, "text"):
                    assistant_content += block.text
            # Store reasoning trace
            node_ids = [r["node"].id for r in results]
            self.db.store_trace(
                query=user_message,
                node_ids_used=node_ids,
                response=assistant_content[:500],
                scope=scope,
            )
            self.db.memorize(content=user_message, entities=entities, scope=scope)
            response_entities = _extract_entities(assistant_content)
            self.db.memorize(content=assistant_content, entities=response_entities, scope=scope)

        return response

    def close(self) -> None:
        self.db.close()

    def __enter__(self) -> "LociAnthropicMemory":
        return self

    def __exit__(self, *exc: Any) -> None:
        self.close()
