"""
HieromemMemory - CrewAI memory integration.

Provides persistent memory for CrewAI agents via HIEROMEM.
"""
from typing import Any, Dict, List, Optional
import httpx


class HieromemMemory:
    """
    Memory backend for CrewAI agents using HIEROMEM.

    Usage:
        from hieromem.integrations.crewai import HieromemMemory

        memory = HieromemMemory(
            hieromem_url="http://localhost:8000",
            crew_id="research_crew"
        )

        # Access via agent
        agent = Agent(
            role="Researcher",
            goal="...",
            backstory="...",
        )
        # Use memory.save() and memory.search()
    """

    def __init__(
        self,
        hieromem_url: str = "http://localhost:8000",
        api_key: Optional[str] = None,
        crew_id: str = "default_crew",
        namespace: str = "crewai",
    ) -> None:
        self.hieromem_url = hieromem_url
        self.api_key = api_key
        self.crew_id = crew_id
        self.namespace = namespace
        self._client = httpx.Client(
            base_url=hieromem_url,
            headers={"Authorization": f"Bearer {api_key}"} if api_key else {},
            timeout=30.0,
        )

    def save(
        self,
        content: str,
        agent_role: Optional[str] = None,
        task_description: Optional[str] = None,
        metadata: Optional[Dict[str, Any]] = None,
    ) -> Optional[str]:
        """
        Save memory from agent execution.

        Args:
            content: The content to save
            agent_role: Role of the agent (e.g., "Researcher")
            task_description: Description of the task being performed
            metadata: Additional metadata

        Returns:
            Episode ID if successful
        """
        meta = {
            "crew_id": self.crew_id,
            "type": "crewai_memory",
            **(metadata or {}),
        }
        if agent_role:
            meta["agent_role"] = agent_role
        if task_description:
            meta["task"] = task_description

        try:
            response = self._client.post(
                "/memory/insert",
                json={
                    "text": content,
                    "namespace": self.namespace,
                    "meta": meta,
                },
            )
            response.raise_for_status()
            result: Optional[str] = response.json().get("episode_id")
            return result
        except httpx.HTTPError:
            return None

    def search(
        self,
        query: str,
        k: int = 5,
        agent_role: Optional[str] = None,
    ) -> List[Dict[str, Any]]:
        """
        Search memories.

        Args:
            query: Search query
            k: Number of results
            agent_role: Filter by agent role (optional)

        Returns:
            List of memory results
        """
        try:
            response = self._client.post(
                "/memory/retrieve",
                json={
                    "query": query,
                    "k": k,
                    "namespace": self.namespace,
                    "mode": "graph_hybrid",
                },
            )
            response.raise_for_status()
            episodes = response.json().get("episodes", [])

            results = []
            for ep in episodes:
                meta = ep.get("meta", {})
                # Filter by agent role if specified
                if agent_role and meta.get("agent_role") != agent_role:
                    continue
                results.append({
                    "id": ep.get("id"),
                    "content": meta.get("text", ""),
                    "agent_role": meta.get("agent_role"),
                    "task": meta.get("task"),
                    "trust": ep.get("trust"),
                })
            return results

        except httpx.HTTPError:
            return []

    def save_task_result(
        self,
        task_description: str,
        result: str,
        agent_role: str,
    ) -> Optional[str]:
        """
        Save a task execution result.

        Args:
            task_description: Description of the completed task
            result: The task result/output
            agent_role: Role of the agent that completed the task

        Returns:
            Episode ID if successful
        """
        content = f"Task: {task_description}\nResult: {result}"
        return self.save(
            content=content,
            agent_role=agent_role,
            task_description=task_description,
            metadata={"type": "task_result"},
        )

    def get_crew_context(
        self,
        query: str = "crew execution context",
        limit: int = 10,
    ) -> str:
        """
        Get aggregated context for the crew.

        Args:
            query: Context query
            limit: Max memories to include

        Returns:
            Formatted context string
        """
        memories = self.search(query, k=limit)
        if not memories:
            return ""

        context_parts = []
        for mem in memories:
            role = mem.get("agent_role", "Unknown")
            content = mem.get("content", "")
            context_parts.append(f"[{role}]: {content}")

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

    def clear(self) -> bool:
        """Clear all memories for this crew."""
        try:
            self._client.delete(f"/memory/namespace/{self.namespace}")
            return True
        except httpx.HTTPError:
            return False

    def __del__(self) -> None:
        if hasattr(self, "_client") and self._client:
            self._client.close()
