"""Asynchronous OctaMem client."""

from __future__ import annotations

import os
from typing import Any, overload

from ._constants import DEFAULT_BASE_URL, DEFAULT_MAX_RETRIES, DEFAULT_RETRY_DELAY, DEFAULT_TIMEOUT, ENDPOINTS
from ._http import AsyncHTTPClient
from ._types import AddParams, AddResult, GetParams, MemoryDetails, SearchResult
from ._validators import validate_api_key


class AsyncOctaMem:
    """
    Asynchronous OctaMem client.

    Provides async access to OctaMem memory API with automatic retries,
    connection pooling, and full type safety.

    Example:
        ```python
        import asyncio
        from octamem import AsyncOctaMem

        async def main():
            # Create client with your API key
            client = AsyncOctaMem(api_key="your-api-key")

            # Search memories
            results = await client.get(query="meeting notes")

            # Add memory (if supported)
            await client.add(content="Remember to call John tomorrow")

            # Get memory details
            details = await client.details()

            await client.close()

        asyncio.run(main())
        ```

    Args:
        api_key: Your OctaMem API key. Can also be set via OCTAMEM_API_KEY environment variable.
        base_url: Base URL for the API. Defaults to https://platform.octamem.com
        timeout: Request timeout in seconds. Defaults to 30.
        max_retries: Maximum retry attempts for failed requests. Defaults to 3.
        retry_delay: Base delay between retries in seconds. Defaults to 1.
    """

    def __init__(
        self,
        api_key: str | None = None,
        *,
        base_url: str = DEFAULT_BASE_URL,
        timeout: float = DEFAULT_TIMEOUT,
        max_retries: int = DEFAULT_MAX_RETRIES,
        retry_delay: float = DEFAULT_RETRY_DELAY,
    ) -> None:
        resolved_api_key = api_key or os.environ.get("OCTAMEM_API_KEY")
        self._api_key = validate_api_key(resolved_api_key)

        self._http = AsyncHTTPClient(
            self._api_key,
            base_url=base_url,
            timeout=timeout,
            max_retries=max_retries,
            retry_delay=retry_delay,
        )

    async def close(self) -> None:
        """Close the client and release resources."""
        await self._http.close()

    async def __aenter__(self) -> "AsyncOctaMem":
        return self

    async def __aexit__(self, *args: Any) -> None:
        await self.close()

    @overload
    async def get(self, *, query: str, previous_context: str = "") -> SearchResult: ...

    @overload
    async def get(self, params: GetParams) -> SearchResult: ...

    async def get(
        self,
        params: GetParams | None = None,
        *,
        query: str | None = None,
        previous_context: str = "",
    ) -> SearchResult:
        """
        Search memories.

        Sends POST /api/memory/search with body: {"query": "...", "previousContext": "..."}.

        Args:
            query: Search query string.
            previous_context: Optional previous context. Sent as previousContext.

        Returns:
            Search results from the memory.
        """
        body: dict[str, Any] = {"query": query or "", "previousContext": previous_context or ""}
        if params is not None:
            body["query"] = params.get("query", body["query"])
            body["previousContext"] = params.get("previousContext", body["previousContext"])

        response = await self._http.request("POST", ENDPOINTS["SEARCH"], body=body)
        return SearchResult.model_validate(response)

    @overload
    async def add(self, *, content: str, previous_context: str = "") -> AddResult: ...

    @overload
    async def add(self, params: AddParams) -> AddResult: ...

    async def add(
        self,
        params: AddParams | None = None,
        *,
        content: str | None = None,
        previous_context: str = "",
    ) -> AddResult:
        """
        Add content to memory.

        Sends POST /api/memory/add with body: {"content": "...", "previousContext": "..."}.

        Args:
            content: Content to store in memory.
            previous_context: Optional previous context. Sent as previousContext.

        Returns:
            Result of the add operation.
        """
        body: dict[str, Any] = {"content": content or "", "previousContext": previous_context or ""}
        if params is not None:
            body["content"] = params.get("content", body["content"])
            body["previousContext"] = params.get("previousContext", body["previousContext"])

        response = await self._http.request("POST", ENDPOINTS["ADD"], body=body)
        return AddResult.model_validate(response)

    async def details(self) -> MemoryDetails:
        """
        Get memory details.

        Sends POST /api/memory/details with body: {}.
        """
        response = await self._http.request("POST", ENDPOINTS["DETAILS"], body={})
        return MemoryDetails.model_validate(response)
