from __future__ import annotations

from typing import TYPE_CHECKING, Any

from ...._constants import EMPTY_JSON
from ...._endpoints import Characters
from ...._internal._schemas import APIEnvelope
from ...._internal._schemas.characters import (
    CharacterDetail,
    CharacterListModels,
    CollectResponse,
)
from ..._base import BaseResource
from .characters_chat import AsyncCharactersChatResource
from .characters_datacards import AsyncCharactersDataCardsResource
from .characters_replies import AsyncCharactersRepliesResource
from .characters_settings import AsyncCharactersSettingsResource

if TYPE_CHECKING:
    from ...._async_client import AsyncClient
else:
    AsyncClient = Any


class AsyncCharactersResource(BaseResource[AsyncClient]):
    """Root resource for character-related API operations (async).

    Accessible via ``client.characters``.

    Sub-resources:

    - ``chats`` — chat sessions and message streaming
    - ``settings`` — global account-level character settings
    - ``datacards`` — user persona profiles attached to chats
    - ``replies`` — AI-suggested reply recommendations
    """

    def __init__(self, client: AsyncClient) -> None:
        super().__init__(client)
        self.chats = AsyncCharactersChatResource(client)
        self.settings = AsyncCharactersSettingsResource(client)
        self.datacards = AsyncCharactersDataCardsResource(client)
        self.replies = AsyncCharactersRepliesResource(client)

    async def follow(
        self,
        character_id: str,
        collection_no: str | None = None,
    ) -> APIEnvelope[CollectResponse]:
        """Follow (collect) a character.

        Args:
            character_id: ID of the character to follow.
            collection_no: Optional collection to add the character to.

        Returns:
            ``APIEnvelope[CollectResponse]`` — ``.value.id`` is the
            follow-record ID needed to :meth:`unfollow` later.

        Example:
            >>> result = await client.characters.follow("char_abc123")
            >>> follow_id = result.value.id
        """
        payload: dict[str, str] = {"character_no": character_id}
        if collection_no is not None:
            payload["collection_no"] = collection_no

        env = await self._client.request_route(Characters.COLLECT, json=payload)
        return APIEnvelope[CollectResponse].model_validate(env)

    async def unfollow(
        self,
        id: str,
    ) -> APIEnvelope[CollectResponse]:
        """Unfollow a previously followed character.

        Args:
            id: Follow-record ID returned by :meth:`follow` (``result.value.id``),
                not the character ID.

        Returns:
            ``APIEnvelope[CollectResponse]`` — ``.value.id`` echoes the
            follow-record ID.

        Example:
            >>> await client.characters.unfollow(follow_id)
        """
        env = await self._client.request_route(
            Characters.COLLECT,
            json={"id": id},
        )
        return APIEnvelope[CollectResponse].model_validate(env)

    async def detail(
        self,
        character_id: str,
    ) -> APIEnvelope[CharacterDetail]:
        """Fetch detailed information about a character.

        Args:
            character_id: ID of the character to look up.

        Returns:
            ``APIEnvelope[CharacterDetail]`` — rich object with character
            metadata: name, persona, tags, follower count, related
            characters, and more.

        Example:
            >>> info = await client.characters.detail("char_abc123")
            >>> print(info.value.name)
        """
        env = await self._client.request_route(
            Characters.DETAIL,
            json={"id": character_id},
        )

        return APIEnvelope[CharacterDetail].model_validate(env)

    async def models(
        self,
    ) -> APIEnvelope[CharacterListModels]:
        """Fetch the list of available AI models for character chats.

        Returns:
            ``APIEnvelope[CharacterListModels]`` — ``.value.List`` contains
            the available models; ``.value.functionality_list`` describes
            per-model feature flags.

        Example:
            >>> result = await client.characters.models()
            >>> for m in result.value.List:
            ...     print(f"{m.gpt_model} | {m.title_key}")
        """
        env = await self._client.request_route(
            Characters.MODELS,
            json=EMPTY_JSON,
        )

        return APIEnvelope[CharacterListModels].model_validate(env)
