from __future__ import annotations

from typing import TYPE_CHECKING, Any

from ...._endpoints import Characters
from ...._internal._schemas import APIEnvelope
from ...._internal._schemas.characters.characters_chat import (
    CreateChatInfo,
    HistoryCharacterChat,
    HistoryCharacterChatBody,
    Message,
    StartChatInfo,
)
from ..._base import BaseResource
from .characters_chat_settings import CharactersChatSettingsResource
from .characters_messages import CharactersMessagesResource

if TYPE_CHECKING:
    from collections.abc import Iterator
    from pathlib import Path
    from types import SimpleNamespace

    from ...._internal._schemas.characters.characters_messages import (
        CharacterChatCompletionResult,
        StreamItem,
        VoiceStreamItem,
    )
    from ...._sync_client import SyncClient
    from ...._types import HistoryInput
else:
    SyncClient = Any


class CharactersChatResource(BaseResource[SyncClient]):
    """Chat session resource for characters (sync).

    Manages the full lifecycle of character chat sessions: creation,
    initialization, messaging, voice synthesis, and deletion.

    Accessible via ``client.characters.chats``.

    Sub-resources:

    - ``messages`` — message history and streaming (delegates for stream/send methods below)
    - ``settings`` — per-session generation parameters (temperature, length, etc.)
    """

    def __init__(self, client: SyncClient) -> None:
        super().__init__(client)
        self.settings = CharactersChatSettingsResource(client)
        self.messages = CharactersMessagesResource(client)

    def create(
        self,
        character_id: str,
        *,
        mask: str = "",
    ) -> APIEnvelope[CreateChatInfo]:
        """Create a new chat session for a character.

        Args:
            character_id: The character to open a session with.
            mask: Internal mask parameter forwarded to the API.

        Returns:
            ``APIEnvelope[CreateChatInfo]`` — ``.value.session_id`` contains
            the new session ID to pass to subsequent calls.

        Example:
            >>> info = client.characters.chats.create("char_abc123")
            >>> session_id = info.value.session_id
        """
        env = self._client.request_route(
            Characters.Chat.CREATE,
            json={"character_id": character_id, "mask": mask},
        )

        return APIEnvelope[CreateChatInfo].model_validate(env)

    def start(
        self,
        session_id: str,
        *,
        dft_timbre_id: str = "",
    ) -> APIEnvelope[StartChatInfo]:
        """Initialize a chat session and retrieve its configuration.

        Returns display settings, voice timbre, free message quota,
        memory flag, and other.

        Args:
            session_id: The session to initialize.
            dft_timbre_id: Default voice ID. Pass an empty string
                (default) to use the character's configured voice.

        Returns:
            ``APIEnvelope[StartChatInfo]`` — ``.value`` contains session
            configuration including ``.free_times``, ``.card``, and
            more.

        Example:
            >>> info = client.characters.chats.start(session_id)
            >>> print(info.value.enable_memory)
        """
        env = self._client.request_route(
            Characters.Chat.START,
            json={"session_id": session_id, "dft_timbre_id": dft_timbre_id},
        )

        return APIEnvelope[StartChatInfo].model_validate(env)

    def stream(
        self,
        content: str,
        session_id: str,
        *,
        character_name: str | None = None,
        model: str = "Gemini-2.5-Flash-Preview-05-20",
        messages: Message | None = None,
        history: HistoryInput | None = None,
        history_server_compat: bool = True,
        vip_only: int = 2,
        support_voice: int = 1,
        refer: str = "v1",
        stream: bool = True,
        ss: int | None = None,
    ) -> Iterator[StreamItem]:
        """Stream a message to the character and receive chunks in real time.

        Shortcut for ``messages.stream()``. See
        ``CharactersMessagesResource`` for the full argument list.
        """
        yield from self.messages.stream(
            content=content,
            session_id=session_id,
            character_name=character_name,
            model=model,
            messages=messages,
            history=history,
            history_server_compat=history_server_compat,
            vip_only=vip_only,
            support_voice=support_voice,
            refer=refer,
            stream=stream,
            ss=ss,
        )

    def stream_raw(
        self,
        content: str,
        session_id: str,
        *,
        character_name: str | None = None,
        model: str = "Gemini-2.5-Flash-Preview-05-20",
        messages: Message | None = None,
        history: HistoryInput | None = None,
        history_server_compat: bool = True,
        vip_only: int = 2,
        support_voice: int = 1,
        refer: str = "v1",
        stream: bool = True,
        ss: int | None = None,
    ) -> Iterator[SimpleNamespace]:
        """Stream raw (unvalidated) SSE events from the character endpoint.

        Shortcut for ``messages.stream_raw()``. See
        ``CharactersMessagesResource`` for the full argument list.
        """
        yield from self.messages.stream_raw(
            content=content,
            session_id=session_id,
            character_name=character_name,
            model=model,
            messages=messages,
            history=history,
            history_server_compat=history_server_compat,
            vip_only=vip_only,
            support_voice=support_voice,
            refer=refer,
            stream=stream,
            ss=ss,
        )

    def stream_tourist(
        self,
        content: str,
        session_id: str,
        *,
        character_name: str | None = None,
        model: str = "Gemini-2.5-Flash-Preview-05-20",
        messages: Message | None = None,
        history: HistoryInput | None = None,
        history_server_compat: bool = True,
        vip_only: int = 2,
        support_voice: int = 1,
        refer: str = "v1",
        stream: bool = True,
        ss: int | None = None,
    ) -> Iterator[StreamItem]:
        """Stream a message using the tourist (unauthenticated) endpoint.

        Shortcut for ``messages.stream_tourist()``. See
        ``CharactersMessagesResource`` for the full argument list.
        """
        yield from self.messages.stream_tourist(
            content=content,
            session_id=session_id,
            character_name=character_name,
            model=model,
            messages=messages,
            history=history,
            history_server_compat=history_server_compat,
            vip_only=vip_only,
            support_voice=support_voice,
            refer=refer,
            stream=stream,
            ss=ss,
        )

    def stream_tourist_raw(
        self,
        content: str,
        session_id: str,
        *,
        character_name: str | None = None,
        model: str = "Gemini-2.5-Flash-Preview-05-20",
        messages: Message | None = None,
        history: HistoryInput | None = None,
        history_server_compat: bool = True,
        vip_only: int = 2,
        support_voice: int = 1,
        refer: str = "v1",
        stream: bool = True,
        ss: int | None = None,
    ) -> Iterator[SimpleNamespace]:
        """Stream raw SSE events from the tourist endpoint.

        Shortcut for ``messages.stream_tourist_raw()``. See
        ``CharactersMessagesResource`` for the full argument list.
        """
        yield from self.messages.stream_tourist_raw(
            content=content,
            session_id=session_id,
            character_name=character_name,
            model=model,
            messages=messages,
            history=history,
            history_server_compat=history_server_compat,
            vip_only=vip_only,
            support_voice=support_voice,
            refer=refer,
            stream=stream,
            ss=ss,
        )

    def send_tourist(
        self,
        content: str,
        session_id: str,
        *,
        character_name: str | None = None,
        model: str = "Gemini-2.5-Flash-Preview-05-20",
        messages: Message | None = None,
        history: HistoryInput | None = None,
        history_server_compat: bool = True,
        vip_only: int = 2,
        support_voice: int = 1,
        refer: str = "v1",
        stream: bool = True,
        ss: int | None = None,
    ) -> CharacterChatCompletionResult:
        """Send a message via the tourist endpoint and collect the full response.

        Shortcut for ``messages.send_tourist()``. See
        ``CharactersMessagesResource`` for the full argument list.
        """
        return self.messages.send_tourist(
            content=content,
            session_id=session_id,
            character_name=character_name,
            model=model,
            messages=messages,
            history=history,
            history_server_compat=history_server_compat,
            vip_only=vip_only,
            support_voice=support_voice,
            refer=refer,
            stream=stream,
            ss=ss,
        )

    def send(
        self,
        content: str,
        session_id: str,
        *,
        character_name: str | None = None,
        model: str = "Gemini-2.5-Flash-Preview-05-20",
        messages: Message | None = None,
        history: HistoryInput | None = None,
        history_server_compat: bool = True,
        vip_only: int = 2,
        support_voice: int = 1,
        refer: str = "v1",
        stream: bool = True,
        ss: int | None = None,
    ) -> CharacterChatCompletionResult:
        """Send a message and collect the full response.

        Shortcut for ``messages.send()``. See
        ``CharactersMessagesResource`` for the full argument list.
        """
        return self.messages.send(
            content=content,
            session_id=session_id,
            character_name=character_name,
            model=model,
            messages=messages,
            history=history,
            history_server_compat=history_server_compat,
            vip_only=vip_only,
            support_voice=support_voice,
            refer=refer,
            stream=stream,
            ss=ss,
        )

    def stream_voice(
        self,
        msg_id: str,
        *,
        sub_msg_id: str | None = None,
        timbre_id: str = "eba3e397c5d5dc7e0324fdd267c8e0ff",
    ) -> Iterator[VoiceStreamItem]:
        """Stream raw voice synthesis chunks for a character message.

        Shortcut for ``messages.stream_voice()``. See
        ``CharactersMessagesResource`` for the full argument list.
        """
        yield from self.messages.stream_voice(
            msg_id=msg_id,
            sub_msg_id=sub_msg_id,
            timbre_id=timbre_id,
        )

    def get_audio(
        self,
        msg_id: str,
        *,
        sub_msg_id: str | None = None,
        timbre_id: str = "eba3e397c5d5dc7e0324fdd267c8e0ff",
    ) -> bytes | None:
        """Fetch synthesized voice audio for a message as raw bytes.

        Shortcut for ``messages.get_audio()``. See
        ``CharactersMessagesResource`` for the full argument list.
        """
        return self.messages.get_audio(
            msg_id=msg_id,
            sub_msg_id=sub_msg_id,
            timbre_id=timbre_id,
        )

    def save_audio(
        self,
        msg_id: str,
        *,
        sub_msg_id: str | None = None,
        timbre_id: str = "eba3e397c5d5dc7e0324fdd267c8e0ff",
        file_path: str | Path | None = None,
    ) -> Path | None:
        """Fetch synthesized voice audio for a message and save it to disk.

        Shortcut for ``messages.save_audio()``. See
        ``CharactersMessagesResource`` for the full argument list.
        """
        return self.messages.save_audio(
            msg_id=msg_id,
            sub_msg_id=sub_msg_id,
            timbre_id=timbre_id,
            file_path=file_path,
        )

    def list(
        self,
        character_id: str,
        *,
        page: int = 1,
        page_size: int = 20,
        with_latest_msg: int = 1,
        ss: int | None = None,
    ) -> APIEnvelope[HistoryCharacterChat]:
        """List chat sessions for a character.

        Args:
            character_id: The character whose sessions to retrieve.
            page: 1-based page number. Defaults to ``1``.
            page_size: Maximum sessions per page. Defaults to ``20``.
            with_latest_msg: When ``1`` (default), each session item
                includes a ``latest_msg`` preview.
            ss: Internal session-state parameter forwarded to the API.

        Returns:
            ``APIEnvelope[HistoryCharacterChat]`` — ``.value.items`` is a
            list of ``Item`` objects (each with ``.session_id``,
            ``.session_title``, ``.latest_msg``, etc.).
            ``.value.has_more`` indicates whether further pages exist.

        Example:
            >>> envelope = client.characters.chats.list("char_abc123")
            >>> for session in envelope.value.items or []:
            ...     print(session.session_id)
        """
        body = HistoryCharacterChatBody(
            character_id=character_id,
            page=page,
            page_size=page_size,
            with_latest_msg=with_latest_msg,
            ss=ss,
        )
        env = self._client.request_route(
            Characters.Chat.LIST,
            json=body.model_dump(exclude_none=True),
        )
        return APIEnvelope[HistoryCharacterChat].model_validate(env)

    def delete(
        self,
        session_id: str,
    ) -> APIEnvelope[None]:
        """Delete a chat session.

        Args:
            session_id: ID of the session to delete.

        Returns:
            ``APIEnvelope[None]`` — no data payload; a successful return
            confirms the session was deleted.

        Example:
            >>> client.characters.chats.delete("sess_abc123")
        """
        return self._client.request_route(
            Characters.Chat.DELETE,
            json={"id": session_id},
        )

    def delete_all(
        self,
        character_id: str,
    ) -> APIEnvelope[None]:
        """Delete all chat sessions for a character.

        Args:
            character_id: The character whose sessions to delete.

        Returns:
            ``APIEnvelope[None]`` — no data payload; a successful return
            confirms all sessions were deleted.

        Example:
            >>> client.characters.chats.delete_all("char_abc123")
        """
        return self._client.request_route(
            Characters.Chat.DELETE_ALL,
            json={"character_id": character_id},
        )
