"""Memory resource for the Cerebe SDK."""

from __future__ import annotations

from typing import TYPE_CHECKING, Any, Literal

from .._response import APIResponse

if TYPE_CHECKING:
    from .._client import AsyncCerebe, Cerebe

MemoryType = Literal[
    "episodic",
    "semantic",
    "procedural",
    "sequential",
    "execution_history",
    "plan",
    "tool_reliability",
    "working",
    "declarative",
]

RelationType = Literal[
    "causes",
    "caused_by",
    "related_to",
    "part_of",
    "similar_to",
    "opposite_of",
    "follows",
    "precedes",
]


class MemoryResource:
    """Sync memory operations."""

    def __init__(self, client: Cerebe) -> None:
        self._client = client

    def add(
        self,
        content: str,
        session_id: str,
        *,
        entity_id: str | None = None,
        type: MemoryType = "semantic",
        importance: float = 0.5,
        metadata: dict[str, Any] | None = None,
    ) -> APIResponse[Any]:
        """Store a memory."""
        body: dict[str, Any] = {
            "content": content,
            "session_id": session_id,
            "memory_type": type,
            "importance": importance,
            "metadata": metadata or {},
        }
        if entity_id:
            body["entity_id"] = entity_id
        return self._client.request("POST", "/api/v1/memory/store", json=body)

    def search(
        self,
        query: str,
        session_id: str,
        *,
        entity_id: str | None = None,
        limit: int = 5,
        types: list[MemoryType] | None = None,
        min_importance: float | None = None,
    ) -> APIResponse[Any]:
        """Search memories by semantic similarity."""
        body: dict[str, Any] = {
            "query": query,
            "session_id": session_id,
            "limit": limit,
        }
        if entity_id:
            body["entity_id"] = entity_id
        if types:
            body["memory_types"] = types
        if min_importance is not None:
            body["min_importance"] = min_importance
        return self._client.request("POST", "/api/v1/memory/search", json=body)

    def get(self, memory_id: str, *, session_id: str) -> APIResponse[Any]:
        """Get a specific memory by ID.

        Args:
            memory_id: The memory ID to retrieve.
            session_id: Session ID (required by the API).
        """
        return self._client.request("GET", f"/api/v1/memory/{memory_id}", params={"session_id": session_id})

    def update(self, memory_id: str, *, session_id: str | None = None, **kwargs: Any) -> APIResponse[Any]:
        """Update a memory's properties."""
        body: dict[str, Any] = {**kwargs}
        if session_id:
            body["session_id"] = session_id
        return self._client.request("PATCH", f"/api/v1/memory/{memory_id}", json=body)

    def delete(self, memory_id: str, *, session_id: str | None = None) -> APIResponse[Any]:
        """Delete a memory."""
        params: dict[str, str] = {}
        if session_id:
            params["session_id"] = session_id
        return self._client.request("DELETE", f"/api/v1/memory/{memory_id}", params=params or None)

    def session(
        self,
        session_id: str,
        *,
        limit: int | None = None,
        memory_types: list[MemoryType] | None = None,
    ) -> APIResponse[Any]:
        """Retrieve all memories for a session."""
        params: dict[str, Any] = {}
        if limit is not None:
            params["limit"] = str(limit)
        if memory_types:
            params["memory_types"] = ",".join(memory_types)
        return self._client.request(
            "GET", f"/api/v1/memory/session/{session_id}", params=params or None
        )

    def relationships(
        self,
        source_id: str,
        target_id: str,
        relation_type: RelationType,
        *,
        strength: float = 1.0,
        metadata: dict[str, Any] | None = None,
    ) -> APIResponse[Any]:
        """Create a relationship between two memories."""
        body: dict[str, Any] = {
            "source_id": source_id,
            "target_id": target_id,
            "relation_type": relation_type,
            "strength": strength,
        }
        if metadata:
            body["metadata"] = metadata
        return self._client.request("POST", "/api/v1/memory/relationships", json=body)

    def query_tune(self, session_id: str, message: str) -> APIResponse[Any]:
        """Tune a query for optimal memory retrieval."""
        return self._client.request(
            "POST",
            "/api/v1/memory/query/tune",
            json={"session_id": session_id, "message": message},
        )

    def harvest(
        self,
        session_id: str,
        transcript: list[dict[str, Any]],
        *,
        entity_id: str | None = None,
        metadata: dict[str, Any] | None = None,
    ) -> APIResponse[Any]:
        """Extract memories from a conversation transcript.

        Args:
            session_id: Session identifier.
            transcript: List of message dicts with 'role' and 'content' keys.
                        Example: [{"role": "user", "content": "hello"}]
        """
        body: dict[str, Any] = {
            "session_id": session_id,
            "transcript": transcript,
        }
        if entity_id:
            body["entity_id"] = entity_id
        if metadata:
            body["metadata"] = metadata
        return self._client.request("POST", "/api/v1/memory/harvest", json=body)

    def consolidate(
        self,
        entity_id: str,
        *,
        similarity_threshold: float = 0.92,
        dry_run: bool = False,
    ) -> APIResponse[Any]:
        """Detect and merge near-duplicate memories."""
        return self._client.request(
            "POST",
            "/api/v1/memory/consolidate",
            json={
                "entity_id": entity_id,
                "similarity_threshold": similarity_threshold,
                "dry_run": dry_run,
            },
        )


class AsyncMemoryResource:
    """Async memory operations."""

    def __init__(self, client: AsyncCerebe) -> None:
        self._client = client

    async def add(
        self,
        content: str,
        session_id: str,
        *,
        entity_id: str | None = None,
        type: MemoryType = "semantic",
        importance: float = 0.5,
        metadata: dict[str, Any] | None = None,
    ) -> APIResponse[Any]:
        """Store a memory."""
        body: dict[str, Any] = {
            "content": content,
            "session_id": session_id,
            "memory_type": type,
            "importance": importance,
            "metadata": metadata or {},
        }
        if entity_id:
            body["entity_id"] = entity_id
        return await self._client.request("POST", "/api/v1/memory/store", json=body)

    async def search(
        self,
        query: str,
        session_id: str,
        *,
        entity_id: str | None = None,
        limit: int = 5,
        types: list[MemoryType] | None = None,
        min_importance: float | None = None,
    ) -> APIResponse[Any]:
        """Search memories by semantic similarity."""
        body: dict[str, Any] = {
            "query": query,
            "session_id": session_id,
            "limit": limit,
        }
        if entity_id:
            body["entity_id"] = entity_id
        if types:
            body["memory_types"] = types
        if min_importance is not None:
            body["min_importance"] = min_importance
        return await self._client.request("POST", "/api/v1/memory/search", json=body)

    async def get(self, memory_id: str, *, session_id: str) -> APIResponse[Any]:
        """Get a specific memory by ID.

        Args:
            memory_id: The memory ID to retrieve.
            session_id: Session ID (required by the API).
        """
        return await self._client.request("GET", f"/api/v1/memory/{memory_id}", params={"session_id": session_id})

    async def update(self, memory_id: str, *, session_id: str | None = None, **kwargs: Any) -> APIResponse[Any]:
        """Update a memory's properties."""
        body: dict[str, Any] = {**kwargs}
        if session_id:
            body["session_id"] = session_id
        return await self._client.request("PATCH", f"/api/v1/memory/{memory_id}", json=body)

    async def delete(self, memory_id: str, *, session_id: str | None = None) -> APIResponse[Any]:
        """Delete a memory."""
        params: dict[str, str] = {}
        if session_id:
            params["session_id"] = session_id
        return await self._client.request("DELETE", f"/api/v1/memory/{memory_id}", params=params or None)

    async def session(
        self,
        session_id: str,
        *,
        limit: int | None = None,
        memory_types: list[MemoryType] | None = None,
    ) -> APIResponse[Any]:
        """Retrieve all memories for a session."""
        params: dict[str, Any] = {}
        if limit is not None:
            params["limit"] = str(limit)
        if memory_types:
            params["memory_types"] = ",".join(memory_types)
        return await self._client.request(
            "GET", f"/api/v1/memory/session/{session_id}", params=params or None
        )

    async def relationships(
        self,
        source_id: str,
        target_id: str,
        relation_type: RelationType,
        *,
        strength: float = 1.0,
        metadata: dict[str, Any] | None = None,
    ) -> APIResponse[Any]:
        """Create a relationship between two memories."""
        body: dict[str, Any] = {
            "source_id": source_id,
            "target_id": target_id,
            "relation_type": relation_type,
            "strength": strength,
        }
        if metadata:
            body["metadata"] = metadata
        return await self._client.request("POST", "/api/v1/memory/relationships", json=body)

    async def query_tune(self, session_id: str, message: str) -> APIResponse[Any]:
        """Tune a query for optimal memory retrieval."""
        return await self._client.request(
            "POST",
            "/api/v1/memory/query/tune",
            json={"session_id": session_id, "message": message},
        )

    async def harvest(
        self,
        session_id: str,
        transcript: list[dict[str, Any]],
        *,
        entity_id: str | None = None,
        metadata: dict[str, Any] | None = None,
    ) -> APIResponse[Any]:
        """Extract memories from a conversation transcript.

        Args:
            session_id: Session identifier.
            transcript: List of message dicts with 'role' and 'content' keys.
                        Example: [{"role": "user", "content": "hello"}]
        """
        body: dict[str, Any] = {
            "session_id": session_id,
            "transcript": transcript,
        }
        if entity_id:
            body["entity_id"] = entity_id
        if metadata:
            body["metadata"] = metadata
        return await self._client.request("POST", "/api/v1/memory/harvest", json=body)

    async def consolidate(
        self,
        entity_id: str,
        *,
        similarity_threshold: float = 0.92,
        dry_run: bool = False,
    ) -> APIResponse[Any]:
        """Detect and merge near-duplicate memories."""
        return await self._client.request(
            "POST",
            "/api/v1/memory/consolidate",
            json={
                "entity_id": entity_id,
                "similarity_threshold": similarity_threshold,
                "dry_run": dry_run,
            },
        )
