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

// This sample shows how to create and use a simple AI agent that stores chat messages in a vector store using the ChatHistoryMemoryProvider.
// It can then use the chat history from prior conversations to inform responses in new conversations.

using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel.Connectors.InMemory;
using OpenAI.Chat;

var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-5.4-mini";
var embeddingDeploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME") ?? "text-embedding-3-large";

// Create a vector store to store the chat messages in.
// For demonstration purposes, we are using an in-memory vector store.
// Replace this with a vector store implementation of your choice that can persist the chat history long term.
VectorStore vectorStore = new InMemoryVectorStore(new InMemoryVectorStoreOptions()
{
    // WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
    // In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
    // latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
    EmbeddingGenerator = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
        .GetEmbeddingClient(embeddingDeploymentName)
        .AsIEmbeddingGenerator()
});

// Create the agent and add the ChatHistoryMemoryProvider to store chat messages in the vector store.
AIAgent agent = new AzureOpenAIClient(
    new Uri(endpoint),
    new DefaultAzureCredential())
    .GetChatClient(deploymentName)
    .AsAIAgent(new ChatClientAgentOptions
    {
        ChatOptions = new() { Instructions = "You are good at telling jokes." },
        Name = "Joker",
        AIContextProviders = [new ChatHistoryMemoryProvider(
            vectorStore,
            collectionName: "chathistory",
            vectorDimensions: 3072,
            // Callback to configure the initial state of the ChatHistoryMemoryProvider.
            // The ChatHistoryMemoryProvider stores its state in the AgentSession and this callback
            // will be called whenever the ChatHistoryMemoryProvider cannot find existing state in the session,
            // typically the first time it is used with a new session.
            session => new ChatHistoryMemoryProvider.State(
                // Configure the scope values under which chat messages will be stored.
                // In this case, we are using a fixed user ID and a unique session ID for each new session.
                storageScope: new() { UserId = "UID1", SessionId = Guid.NewGuid().ToString() },
                // Configure the scope which would be used to search for relevant prior messages.
                // In this case, we are searching for any messages for the user across all sessions.
                searchScope: new() { UserId = "UID1" }))]
    });

// Start a new session for the agent conversation.
AgentSession session = await agent.CreateSessionAsync();

// Run the agent with the session that stores conversation history in the vector store.
Console.WriteLine(await agent.RunAsync("I like jokes about Pirates. Tell me a joke about a pirate.", session));

// Start a second session. Since we configured the search scope to be across all sessions for the user,
// the agent should remember that the user likes pirate jokes.
AgentSession? session2 = await agent.CreateSessionAsync();

// Run the agent with the second session.
Console.WriteLine(await agent.RunAsync("Tell me a joke that I might like.", session2));
