"""Character chat — streaming responses token by token.

In this example, we:
  - Stream a character response in real time, printing each chunk
  - Show raw SSE streaming for low-level access
  - Show tourist streaming without authentication

Streaming yields two event types:
  - "chunk" — a partial response fragment (.content holds the text)
  - "end"   — final event with metadata (.response_msg_id, .my_msg_id)

Use stream() when you need real-time output (chat UIs, bots, CLI tools).
Use send() from characters_chat.py when you only need the final result.

It is recommended to use AppId.APP when interacting with characters.

Requires:
    SEAART_EMAIL and SEAART_PASSWORD environment variables.
    No credentials needed for tourist_stream().
"""

from __future__ import annotations

import os

from seaart import SyncClient
from seaart.helpers import extract_character_link
from seaart.types import AppId

CHARACTER_URL = (
    "https://www.seaart.ai/ru/character/chat/d5f5v2te878c73cmjhhg?from=null&s_id=123"
)


# ---------------------------------------------------------------------------
# Basic streaming
# ---------------------------------------------------------------------------


def basic_stream() -> None:
    """Stream a response and print each chunk as it arrives."""
    link = extract_character_link(CHARACTER_URL)
    assert link is not None
    character_id = link.character_id

    with SyncClient(app_id=AppId.APP) as client:
        client.auth.login(
            email=os.environ["SEAART_EMAIL"],
            password=os.environ["SEAART_PASSWORD"],
        )

        chat = client.characters.chats.create(character_id)
        session_id = chat.value.session_id

        try:
            for item in client.characters.chats.stream(
                "Tell me a short story.",
                session_id,
            ):
                if item.event == "chunk":
                    print(item.content, end="", flush=True)
                elif item.event == "end":
                    print(f"\n\n[msg_id={item.response_msg_id}]")
        finally:
            client.characters.chats.delete(session_id)


# ---------------------------------------------------------------------------
# Raw SSE stream
# ---------------------------------------------------------------------------


def raw_stream() -> None:
    """Access raw SSE events without Pydantic validation.

    stream_raw() yields SimpleNamespace objects with .event, .data, and
    .headers attributes. Useful for debugging or when you need fields
    that the typed models don't expose.
    """
    link = extract_character_link(CHARACTER_URL)
    assert link is not None
    character_id = link.character_id

    with SyncClient(app_id=AppId.APP) as client:
        client.auth.login(
            email=os.environ["SEAART_EMAIL"],
            password=os.environ["SEAART_PASSWORD"],
        )

        chat = client.characters.chats.create(character_id)
        session_id = chat.value.session_id

        try:
            for event in client.characters.chats.stream_raw(
                "Hello!",
                session_id,
            ):
                print(f"event={event.event}  data={event.data}")
        finally:
            client.characters.chats.delete(session_id)


# ---------------------------------------------------------------------------
# Tourist streaming (no account)
# ---------------------------------------------------------------------------


def tourist_stream() -> None:
    """Stream a response without authentication.

    Tourist streams have a limited message quota.
    """
    link = extract_character_link(CHARACTER_URL)
    assert link is not None
    character_id = link.character_id

    with SyncClient(app_id=AppId.APP, default_headers={"x-device-id": "cf51e64c-30ec-453d-9c5c-5357ef159127"}) as client:
        chat = client.characters.chats.create(character_id)
        session_id = chat.value.session_id

        for item in client.characters.chats.stream_tourist(
            "Hello!",
            session_id,
        ):
            if item.event == "chunk":
                print(item.content, end="", flush=True)
        print()


if __name__ == "__main__":
    basic_stream()