using FluentAssertions;
using CatalogService.Domain.AggregatesModel.SampleAggregate;
using CatalogService.Domain.Exceptions;
using Xunit;

namespace CatalogService.UnitTests.Domain;

/// <summary>
/// EN: Unit tests for Sample aggregate.
/// VI: Unit tests cho Sample aggregate.
/// </summary>
public class SampleAggregateTests
{
    [Fact]
    public void CreateSample_WithValidName_ShouldCreateWithDraftStatus()
    {
        // Arrange
        var name = "Test Sample";
        var description = "Test Description";

        // Act
        var sample = new Sample(name, description);

        // Assert
        sample.Name.Should().Be(name);
        sample.Description.Should().Be(description);
        sample.Status.Should().Be(SampleStatus.Draft);
        sample.Id.Should().NotBeEmpty();
        sample.DomainEvents.Should().ContainSingle(); // SampleCreatedDomainEvent
    }

    [Fact]
    public void CreateSample_WithEmptyName_ShouldThrowException()
    {
        // Arrange
        var name = "";

        // Act
        var act = () => new Sample(name);

        // Assert
        act.Should().Throw<SampleDomainException>()
            .WithMessage("Sample name cannot be empty");
    }

    [Fact]
    public void Activate_WhenDraft_ShouldChangeToActive()
    {
        // Arrange
        var sample = new Sample("Test Sample");
        sample.ClearDomainEvents();

        // Act
        sample.Activate();

        // Assert
        sample.Status.Should().Be(SampleStatus.Active);
        sample.DomainEvents.Should().ContainSingle(); // SampleStatusChangedDomainEvent
    }

    [Fact]
    public void Activate_WhenNotDraft_ShouldThrowException()
    {
        // Arrange
        var sample = new Sample("Test Sample");
        sample.Activate();

        // Act
        var act = () => sample.Activate();

        // Assert
        act.Should().Throw<SampleDomainException>()
            .WithMessage("Only draft samples can be activated");
    }

    [Fact]
    public void Complete_WhenActive_ShouldChangeToCompleted()
    {
        // Arrange
        var sample = new Sample("Test Sample");
        sample.Activate();
        sample.ClearDomainEvents();

        // Act
        sample.Complete();

        // Assert
        sample.Status.Should().Be(SampleStatus.Completed);
    }

    [Fact]
    public void Cancel_WhenDraftOrActive_ShouldChangeToCancelled()
    {
        // Arrange
        var sample = new Sample("Test Sample");

        // Act
        sample.Cancel();

        // Assert
        sample.Status.Should().Be(SampleStatus.Cancelled);
    }

    [Fact]
    public void Cancel_WhenCompleted_ShouldThrowException()
    {
        // Arrange
        var sample = new Sample("Test Sample");
        sample.Activate();
        sample.Complete();

        // Act
        var act = () => sample.Cancel();

        // Assert
        act.Should().Throw<SampleDomainException>()
            .WithMessage("Cannot cancel a completed sample");
    }

    [Fact]
    public void Update_WhenNotCancelled_ShouldUpdateNameAndDescription()
    {
        // Arrange
        var sample = new Sample("Original Name", "Original Description");
        var newName = "Updated Name";
        var newDescription = "Updated Description";

        // Act
        sample.Update(newName, newDescription);

        // Assert
        sample.Name.Should().Be(newName);
        sample.Description.Should().Be(newDescription);
        sample.UpdatedAt.Should().NotBeNull();
    }

    [Fact]
    public void Update_WhenCancelled_ShouldThrowException()
    {
        // Arrange
        var sample = new Sample("Test Sample");
        sample.Cancel();

        // Act
        var act = () => sample.Update("New Name", null);

        // Assert
        act.Should().Throw<SampleDomainException>()
            .WithMessage("Cannot update a cancelled sample");
    }
}
