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

using System;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Agents.CopilotStudio.Client;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Agents.Copilot;
using Moq;
using Xunit;
namespace SemanticKernel.Agents.UnitTests.Copilot;

public sealed class CopilotStudioAgentExtensionsTests
{
    [Fact]
    public void AsAIAgent_WithValidCopilotStudioAgent_ReturnsSemanticKernelAIAgent()
    {
        // Arrange
        var clientMock = new Mock<CopilotClient>(null, null, null, null);
        var copilotStudioAgent = new CopilotStudioAgent(clientMock.Object);

        // Act
        var result = copilotStudioAgent.AsAIAgent();

        // Assert
        Assert.NotNull(result);
        Assert.IsType<SemanticKernelAIAgent>(result);
    }

    [Fact]
    public void AsAIAgent_WithNullCopilotStudioAgent_ThrowsArgumentNullException()
    {
        // Arrange
        CopilotStudioAgent nullAgent = null!;

        // Act & Assert
        Assert.Throws<ArgumentNullException>(() => nullAgent.AsAIAgent());
    }

    [Fact]
    public async Task AsAIAgent_CreatesWorkingThreadFactory()
    {
        // Arrange
        var clientMock = new Mock<CopilotClient>(null, null, null, null);
        var copilotStudioAgent = new CopilotStudioAgent(clientMock.Object);

        // Act
        var result = copilotStudioAgent.AsAIAgent();
        var thread = await result.CreateSessionAsync();

        // Assert
        Assert.NotNull(thread);
        Assert.IsType<SemanticKernelAIAgentSession>(thread);
        var threadAdapter = (SemanticKernelAIAgentSession)thread;
        Assert.IsType<CopilotStudioAgentThread>(threadAdapter.InnerThread);
    }

    [Fact]
    public async Task AsAIAgent_ThreadDeserializationFactory_WithNullAgentId_CreatesNewThread()
    {
        // Arrange
        var clientMock = new Mock<CopilotClient>(null, null, null, null);
        var copilotStudioAgent = new CopilotStudioAgent(clientMock.Object);
        var jsonElement = JsonSerializer.SerializeToElement((string?)null);

        // Act
        var result = copilotStudioAgent.AsAIAgent();
        var thread = await result.DeserializeSessionAsync(jsonElement);

        // Assert
        Assert.NotNull(thread);
        Assert.IsType<SemanticKernelAIAgentSession>(thread);
        var threadAdapter = (SemanticKernelAIAgentSession)thread;
        Assert.IsType<CopilotStudioAgentThread>(threadAdapter.InnerThread);
    }

    [Fact]
    public async Task AsAIAgent_ThreadDeserializationFactory_WithValidAgentId_CreatesThreadWithId()
    {
        // Arrange
        var clientMock = new Mock<CopilotClient>(null, null, null, null);
        var copilotStudioAgent = new CopilotStudioAgent(clientMock.Object);
        var agentId = "test-agent-id";
        var jsonElement = JsonSerializer.SerializeToElement(agentId);

        // Act
        var result = copilotStudioAgent.AsAIAgent();
        var thread = await result.DeserializeSessionAsync(jsonElement);

        // Assert
        Assert.NotNull(thread);
        Assert.IsType<SemanticKernelAIAgentSession>(thread);
        var threadAdapter = (SemanticKernelAIAgentSession)thread;
        Assert.IsType<CopilotStudioAgentThread>(threadAdapter.InnerThread);
    }

    [Fact]
    public async Task AsAIAgent_ThreadSerializer_SerializesThreadId()
    {
        // Arrange
        var clientMock = new Mock<CopilotClient>(null, null, null, null);
        var copilotStudioAgent = new CopilotStudioAgent(clientMock.Object);
        var expectedThreadId = "test-thread-id";
        var copilotStudioThread = new CopilotStudioAgentThread(clientMock.Object, expectedThreadId);
        var jsonElement = JsonSerializer.SerializeToElement(expectedThreadId);

        var result = copilotStudioAgent.AsAIAgent();
        var thread = await result.DeserializeSessionAsync(jsonElement);

        // Act
        var serializedElement = await result.SerializeSessionAsync(thread);

        // Assert
        Assert.Equal(JsonValueKind.String, serializedElement.ValueKind);
        Assert.Equal(expectedThreadId, serializedElement.GetString());
    }
}
