"""Advanced chat usage examples

Demonstrates tool calling, async client, reasoning, and error handling.
"""

import asyncio
from octen import Octen, AsyncOcten
from octen import OctenAuthenticationError, OctenRateLimitError, OctenStreamError
from octen.models import ChatMessage, Tool, ToolFunction, ResponseFormat


# -- Tool calling --------------------------------------------------------------

def example_tool_calling():
    """Demonstrate function/tool calling."""
    print("=== Tool Calling ===\n")

    weather_tool = Tool(
        function=ToolFunction(
            name="get_weather",
            description="Get real-time weather for a city",
            parameters={
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "City name, e.g. 'London'"},
                    "unit": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                        "description": "Temperature unit",
                    },
                },
                "required": ["city"],
            },
        )
    )

    with Octen(api_key="octen-your-key") as client:
        messages = [ChatMessage(role="user", content="What's the weather in London?")]
        response = client.chat.create(
            model="openai/gpt-5.4",
            messages=messages,
            tools=[weather_tool],
            tool_choice="auto",
            web_search="off",
        )

        choice = response.choices[0]
        if choice.finish_reason == "tool_calls" and choice.message.tool_calls:
            tc = choice.message.tool_calls[0]
            print(f"Model called tool: {tc.function.name}")
            print(f"Arguments: {tc.function.arguments}")

            messages.append(ChatMessage(
                role="assistant",
                content=choice.message.content or "",
                tool_calls=[tc],
            ))
            messages.append(ChatMessage(
                role="tool",
                content='{"city": "London", "temperature": "18C", "condition": "Cloudy"}',
                tool_call_id=tc.id,
            ))

            final = client.chat.create(
                model="openai/gpt-5.4",
                messages=messages,
                web_search="off",
            )
            print(f"Final answer: {final.text}")
        else:
            print(f"Direct answer: {choice.message.content}")


# -- JSON output mode ----------------------------------------------------------

def example_json_output():
    """Request structured JSON output."""
    print("\n=== JSON Output Mode ===\n")

    with Octen(api_key="octen-your-key") as client:
        response = client.chat.create(
            model="google/gemini-3-flash-preview",
            messages=[
                ChatMessage(
                    role="user",
                    content="Return three programming languages and their main use cases as JSON: [{name, use_case}]",
                )
            ],
            response_format=ResponseFormat(type="json_object"),
            web_search="off",
        )
        print(f"JSON response:\n{response.text}")


# -- Async client --------------------------------------------------------------

async def example_async():
    """Async client with concurrent requests."""
    print("\n=== Async Client ===\n")

    async with AsyncOcten(api_key="octen-your-key") as client:
        task1 = client.chat.create(
            model="openai/gpt-5.4",
            messages=[ChatMessage(role="user", content="Explain deep learning in one sentence")],
            web_search="off",
            max_tokens=50,
        )
        task2 = client.chat.create(
            model="openai/gpt-5.4",
            messages=[ChatMessage(role="user", content="Explain reinforcement learning in one sentence")],
            web_search="off",
            max_tokens=50,
        )
        r1, r2 = await asyncio.gather(task1, task2)
        print(f"Deep learning:          {r1.text}")
        print(f"Reinforcement learning: {r2.text}")


async def example_async_stream():
    """Async streaming."""
    print("\n=== Async Streaming ===\n")

    async with AsyncOcten(api_key="octen-your-key") as client:
        stream = await client.chat.create(
            model="openai/gpt-5.4",
            messages=[ChatMessage(role="user", content="Write a Python hello world program")],
            stream=True,
            web_search="off",
        )
        print("Answer: ", end="", flush=True)
        async for event in stream:
            if event.type == "content" and event.choices:
                print(event.choices[0].delta.content or "", end="", flush=True)
        print()


# -- Error handling ------------------------------------------------------------

def example_error_handling():
    """Demonstrate proper exception handling."""
    print("\n=== Error Handling ===\n")

    try:
        with Octen(api_key="invalid-key") as client:
            client.chat.create(
                model="openai/gpt-5.4",
                messages=[ChatMessage(role="user", content="Hello")],
            )
    except OctenAuthenticationError as e:
        print(f"Auth error (expected): {e}")

    try:
        with Octen(api_key="octen-your-key") as client:
            for event in client.chat.create(
                model="openai/gpt-5.4",
                messages=[ChatMessage(role="user", content="Hello")],
                stream=True,
            ):
                if event.type == "content" and event.choices:
                    print(event.choices[0].delta.content or "", end="", flush=True)
    except OctenStreamError as e:
        print(f"\nStream error: {e} (code={e.code})")
    except OctenRateLimitError as e:
        print(f"\nRate limited -- retry after {e.retry_after}s")


if __name__ == "__main__":
    example_tool_calling()
    example_json_output()
    asyncio.run(example_async())
    asyncio.run(example_async_stream())
    example_error_handling()
