// Copyright (c) Microsoft. All rights reserved.

// This sample demonstrates how to maintain conversation state using the OpenAIResponseClientAgent
// and AgentSession. By passing the same session to multiple agent invocations, the agent
// automatically maintains the conversation history, allowing the AI model to understand
// context from previous exchanges.

using System.ClientModel;
using System.ClientModel.Primitives;
using System.Text.Json;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using OpenAI;
using OpenAI.Chat;
using OpenAI.Conversations;

string apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new InvalidOperationException("OPENAI_API_KEY is not set.");
string model = Environment.GetEnvironmentVariable("OPENAI_CHAT_MODEL_NAME") ?? "gpt-5.4-mini";

// Create a ConversationClient directly from OpenAIClient
OpenAIClient openAIClient = new(apiKey);
ConversationClient conversationClient = openAIClient.GetConversationClient();

// Create an agent directly from the ResponsesClient using OpenAIResponseClientAgent
ChatClientAgent agent = new(openAIClient.GetResponsesClient().AsIChatClient(model), instructions: "You are a helpful assistant.", name: "ConversationAgent");

ClientResult createConversationResult = await conversationClient.CreateConversationAsync(BinaryContent.Create(BinaryData.FromString("{}")));

using JsonDocument createConversationResultAsJson = JsonDocument.Parse(createConversationResult.GetRawResponse().Content.ToString());
string conversationId = createConversationResultAsJson.RootElement.GetProperty("id"u8)!.GetString()!;

// Create a session for the conversation - this enables conversation state management for subsequent turns
AgentSession session = await agent.CreateSessionAsync(conversationId);

Console.WriteLine("=== Multi-turn Conversation Demo ===\n");

// First turn: Ask about a topic
Console.WriteLine("User: What is the capital of France?");
UserChatMessage firstMessage = new("What is the capital of France?");

// After this call, the conversation state associated in the options is stored in 'session' and used in subsequent calls
ChatCompletion firstResponse = await agent.RunAsync([firstMessage], session);
Console.WriteLine($"Assistant: {firstResponse.Content.Last().Text}\n");

// Second turn: Follow-up question that relies on conversation context
Console.WriteLine("User: What famous landmarks are located there?");
UserChatMessage secondMessage = new("What famous landmarks are located there?");

ChatCompletion secondResponse = await agent.RunAsync([secondMessage], session);
Console.WriteLine($"Assistant: {secondResponse.Content.Last().Text}\n");

// Third turn: Another follow-up that demonstrates context continuity
Console.WriteLine("User: How tall is the most famous one?");
UserChatMessage thirdMessage = new("How tall is the most famous one?");

ChatCompletion thirdResponse = await agent.RunAsync([thirdMessage], session);
Console.WriteLine($"Assistant: {thirdResponse.Content.Last().Text}\n");

Console.WriteLine("=== End of Conversation ===");

// Show full conversation history
Console.WriteLine("Full Conversation History:");
ClientResult getConversationResult = await conversationClient.GetConversationAsync(conversationId);

Console.WriteLine("Conversation created.");
Console.WriteLine($"    Conversation ID: {conversationId}");
Console.WriteLine();

CollectionResult getConversationItemsResults = conversationClient.GetConversationItems(conversationId);
foreach (ClientResult result in getConversationItemsResults.GetRawPages())
{
    Console.WriteLine("Message contents retrieved. Order is most recent first by default.");
    using JsonDocument getConversationItemsResultAsJson = JsonDocument.Parse(result.GetRawResponse().Content.ToString());
    foreach (JsonElement element in getConversationItemsResultAsJson.RootElement.GetProperty("data").EnumerateArray())
    {
        // Skip non-message items (e.g. tool calls, reasoning) that lack a "role" property
        if (!element.TryGetProperty("role"u8, out var roleElement))
        {
            continue;
        }

        string messageId = element.GetProperty("id"u8).ToString();
        string messageRole = roleElement.ToString();
        Console.WriteLine($"    Message ID: {messageId}");
        Console.WriteLine($"    Message Role: {messageRole}");

        if (element.TryGetProperty("content"u8, out var contentElement))
        {
            foreach (var content in contentElement.EnumerateArray())
            {
                if (content.TryGetProperty("text"u8, out var textElement))
                {
                    Console.WriteLine($"    Message Text: {textElement}");
                }
            }
        }

        Console.WriteLine();
    }
}

ClientResult deleteConversationResult = conversationClient.DeleteConversation(conversationId);
using JsonDocument deleteConversationResultAsJson = JsonDocument.Parse(deleteConversationResult.GetRawResponse().Content.ToString());
bool deleted = deleteConversationResultAsJson.RootElement
    .GetProperty("deleted"u8)
    .GetBoolean();

Console.WriteLine("Conversation deleted.");
Console.WriteLine($"    Deleted: {deleted}");
Console.WriteLine();
