using ColaFlow.API.Services;
using FluentAssertions;
using Moq;

namespace ColaFlow.API.Tests.Services;

public class ProjectNotificationServiceAdapterTests
{
    private readonly Mock<IRealtimeNotificationService> _mockRealtimeService;
    private readonly ProjectNotificationServiceAdapter _adapter;

    public ProjectNotificationServiceAdapterTests()
    {
        _mockRealtimeService = new Mock<IRealtimeNotificationService>();
        _adapter = new ProjectNotificationServiceAdapter(_mockRealtimeService.Object);
    }

    [Fact]
    public async Task NotifyProjectCreated_CallsRealtimeService()
    {
        // Arrange
        var tenantId = Guid.NewGuid();
        var projectId = Guid.NewGuid();
        var project = new { Id = projectId, Name = "Test Project" };

        // Act
        await _adapter.NotifyProjectCreated(tenantId, projectId, project);

        // Assert
        _mockRealtimeService.Verify(s => s.NotifyProjectCreated(
            tenantId,
            projectId,
            project), Times.Once);
    }

    [Fact]
    public async Task NotifyProjectUpdated_CallsRealtimeService()
    {
        // Arrange
        var tenantId = Guid.NewGuid();
        var projectId = Guid.NewGuid();
        var project = new { Id = projectId, Name = "Updated Project" };

        // Act
        await _adapter.NotifyProjectUpdated(tenantId, projectId, project);

        // Assert
        _mockRealtimeService.Verify(s => s.NotifyProjectUpdated(
            tenantId,
            projectId,
            project), Times.Once);
    }

    [Fact]
    public async Task NotifyProjectArchived_CallsRealtimeService()
    {
        // Arrange
        var tenantId = Guid.NewGuid();
        var projectId = Guid.NewGuid();

        // Act
        await _adapter.NotifyProjectArchived(tenantId, projectId);

        // Assert
        _mockRealtimeService.Verify(s => s.NotifyProjectArchived(
            tenantId,
            projectId), Times.Once);
    }

    [Fact]
    public async Task Adapter_MultipleOperations_AllDelegatedCorrectly()
    {
        // Arrange
        var tenantId = Guid.NewGuid();
        var projectId1 = Guid.NewGuid();
        var projectId2 = Guid.NewGuid();
        var project1 = new { Id = projectId1, Name = "Project 1" };
        var project2 = new { Id = projectId2, Name = "Project 2" };

        // Act
        await _adapter.NotifyProjectCreated(tenantId, projectId1, project1);
        await _adapter.NotifyProjectUpdated(tenantId, projectId2, project2);
        await _adapter.NotifyProjectArchived(tenantId, projectId1);

        // Assert
        _mockRealtimeService.Verify(s => s.NotifyProjectCreated(
            tenantId, projectId1, project1), Times.Once);
        _mockRealtimeService.Verify(s => s.NotifyProjectUpdated(
            tenantId, projectId2, project2), Times.Once);
        _mockRealtimeService.Verify(s => s.NotifyProjectArchived(
            tenantId, projectId1), Times.Once);
    }

    [Fact]
    public async Task NotifyProjectCreated_WithNullProject_StillCallsRealtimeService()
    {
        // Arrange
        var tenantId = Guid.NewGuid();
        var projectId = Guid.NewGuid();

        // Act
        await _adapter.NotifyProjectCreated(tenantId, projectId, null!);

        // Assert
        _mockRealtimeService.Verify(s => s.NotifyProjectCreated(
            tenantId,
            projectId,
            null!), Times.Once);
    }

    [Fact]
    public async Task Adapter_PreservesParameterValues()
    {
        // Arrange
        var tenantId = Guid.NewGuid();
        var projectId = Guid.NewGuid();
        var project = new { Id = projectId, Name = "Test", Status = "Active", CreatedBy = "User1" };

        Guid capturedTenantId = Guid.Empty;
        Guid capturedProjectId = Guid.Empty;
        object? capturedProject = null;

        _mockRealtimeService
            .Setup(s => s.NotifyProjectCreated(It.IsAny<Guid>(), It.IsAny<Guid>(), It.IsAny<object>()))
            .Callback<Guid, Guid, object>((tid, pid, proj) =>
            {
                capturedTenantId = tid;
                capturedProjectId = pid;
                capturedProject = proj;
            })
            .Returns(Task.CompletedTask);

        // Act
        await _adapter.NotifyProjectCreated(tenantId, projectId, project);

        // Assert
        capturedTenantId.Should().Be(tenantId);
        capturedProjectId.Should().Be(projectId);
        capturedProject.Should().BeSameAs(project);
    }
}
