using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;
using FluentAssertions;

namespace ColaFlow.Domain.Tests.ValueObjects;

/// <summary>
/// Unit tests for strongly-typed ID value objects (EpicId, StoryId, TaskId, UserId)
/// </summary>
public class StronglyTypedIdTests
{
    #region EpicId Tests

    [Fact]
    public void EpicId_Create_WithoutParameter_ShouldGenerateNewGuid()
    {
        // Act
        var epicId = EpicId.Create();

        // Assert
        epicId.Should().NotBeNull();
        epicId.Value.Should().NotBe(Guid.Empty);
    }

    [Fact]
    public void EpicId_Create_WithGuid_ShouldCreateEpicIdWithGivenValue()
    {
        // Arrange
        var guid = Guid.NewGuid();

        // Act
        var epicId = EpicId.Create(guid);

        // Assert
        epicId.Value.Should().Be(guid);
    }

    [Fact]
    public void EpicId_Equals_WithSameValue_ShouldReturnTrue()
    {
        // Arrange
        var guid = Guid.NewGuid();
        var epicId1 = EpicId.Create(guid);
        var epicId2 = EpicId.Create(guid);

        // Act & Assert
        epicId1.Should().Be(epicId2);
    }

    #endregion

    #region StoryId Tests

    [Fact]
    public void StoryId_Create_WithoutParameter_ShouldGenerateNewGuid()
    {
        // Act
        var storyId = StoryId.Create();

        // Assert
        storyId.Should().NotBeNull();
        storyId.Value.Should().NotBe(Guid.Empty);
    }

    [Fact]
    public void StoryId_Create_WithGuid_ShouldCreateStoryIdWithGivenValue()
    {
        // Arrange
        var guid = Guid.NewGuid();

        // Act
        var storyId = StoryId.Create(guid);

        // Assert
        storyId.Value.Should().Be(guid);
    }

    [Fact]
    public void StoryId_Equals_WithSameValue_ShouldReturnTrue()
    {
        // Arrange
        var guid = Guid.NewGuid();
        var storyId1 = StoryId.Create(guid);
        var storyId2 = StoryId.Create(guid);

        // Act & Assert
        storyId1.Should().Be(storyId2);
    }

    #endregion

    #region TaskId Tests

    [Fact]
    public void TaskId_Create_WithoutParameter_ShouldGenerateNewGuid()
    {
        // Act
        var taskId = TaskId.Create();

        // Assert
        taskId.Should().NotBeNull();
        taskId.Value.Should().NotBe(Guid.Empty);
    }

    [Fact]
    public void TaskId_Create_WithGuid_ShouldCreateTaskIdWithGivenValue()
    {
        // Arrange
        var guid = Guid.NewGuid();

        // Act
        var taskId = TaskId.Create(guid);

        // Assert
        taskId.Value.Should().Be(guid);
    }

    [Fact]
    public void TaskId_Equals_WithSameValue_ShouldReturnTrue()
    {
        // Arrange
        var guid = Guid.NewGuid();
        var taskId1 = TaskId.Create(guid);
        var taskId2 = TaskId.Create(guid);

        // Act & Assert
        taskId1.Should().Be(taskId2);
    }

    #endregion

    #region UserId Tests

    [Fact]
    public void UserId_Create_WithoutParameter_ShouldGenerateNewGuid()
    {
        // Act
        var userId = UserId.Create();

        // Assert
        userId.Should().NotBeNull();
        userId.Value.Should().NotBe(Guid.Empty);
    }

    [Fact]
    public void UserId_Create_WithGuid_ShouldCreateUserIdWithGivenValue()
    {
        // Arrange
        var guid = Guid.NewGuid();

        // Act
        var userId = UserId.Create(guid);

        // Assert
        userId.Value.Should().Be(guid);
    }

    [Fact]
    public void UserId_Equals_WithSameValue_ShouldReturnTrue()
    {
        // Arrange
        var guid = Guid.NewGuid();
        var userId1 = UserId.Create(guid);
        var userId2 = UserId.Create(guid);

        // Act & Assert
        userId1.Should().Be(userId2);
    }

    #endregion

    #region Type Safety Tests

    [Fact]
    public void DifferentIdTypes_WithSameGuid_ShouldNotBeEqual()
    {
        // Arrange
        var guid = Guid.NewGuid();
        var projectId = ProjectId.Create(guid);
        var epicId = EpicId.Create(guid);

        // Act & Assert - They are different types, so should not be equal
        projectId.Should().NotBe((object)epicId);
    }

    [Fact]
    public void MultipleCalls_ShouldGenerateDifferentGuids()
    {
        // Act
        var id1 = ProjectId.Create();
        var id2 = ProjectId.Create();
        var id3 = EpicId.Create();
        var id4 = StoryId.Create();
        var id5 = TaskId.Create();

        // Assert
        id1.Value.Should().NotBe(id2.Value);
        id1.Value.Should().NotBe(id3.Value);
        id1.Value.Should().NotBe(id4.Value);
        id1.Value.Should().NotBe(id5.Value);
    }

    #endregion
}
