using FluentAssertions;
using MembershipService.Domain.AggregatesModel.ExperienceAggregate;
using Xunit;

namespace MembershipService.UnitTests.Domain;

/// <summary>
/// EN: Unit tests for ExperienceTransaction entity.
/// VI: Unit tests cho ExperienceTransaction entity.
/// </summary>
public class ExperienceTransactionTests
{
    [Fact]
    public void Create_WithValidParameters_ShouldCreateTransaction()
    {
        // Arrange
        var memberId = Guid.NewGuid();

        // Act
        var transaction = new ExperienceTransaction(memberId, 50, ExperienceSource.Purchase, 1);

        // Assert
        transaction.MemberId.Should().Be(memberId);
        transaction.Points.Should().Be(50);
        transaction.Source.Should().Be(ExperienceSource.Purchase);
        transaction.SourceId.Should().Be(ExperienceSource.Purchase.Id);
        transaction.LevelAtTime.Should().Be(1);
    }

    [Fact]
    public void Create_WithReferenceId_ShouldSetReferenceId()
    {
        // Arrange & Act
        var transaction = new ExperienceTransaction(
            Guid.NewGuid(), 100, ExperienceSource.Purchase, 1, "ORDER-123");

        // Assert
        transaction.ReferenceId.Should().Be("ORDER-123");
    }

    [Fact]
    public void Create_WithMetadata_ShouldSetMetadata()
    {
        // Arrange
        var metadata = "{\"orderId\": \"123\", \"items\": 5}";

        // Act
        var transaction = new ExperienceTransaction(
            Guid.NewGuid(), 100, ExperienceSource.Purchase, 1, "ORDER-123", metadata);

        // Assert
        transaction.Metadata.Should().Be(metadata);
    }

    [Fact]
    public void Create_WithNegativePoints_ShouldThrow()
    {
        // Act & Assert
        var act = () => new ExperienceTransaction(Guid.NewGuid(), -50, ExperienceSource.Purchase, 1);
        act.Should().Throw<ArgumentException>().WithMessage("*positive*");
    }

    [Fact]
    public void Create_WithZeroPoints_ShouldThrow()
    {
        // Act & Assert
        var act = () => new ExperienceTransaction(Guid.NewGuid(), 0, ExperienceSource.Purchase, 1);
        act.Should().Throw<ArgumentException>().WithMessage("*positive*");
    }

    [Fact]
    public void Create_WithNullSource_ShouldThrow()
    {
        // Act & Assert
        var act = () => new ExperienceTransaction(Guid.NewGuid(), 50, null!, 1);
        act.Should().Throw<ArgumentNullException>();
    }

    [Fact]
    public void Create_WithEmptyMemberId_ShouldThrow()
    {
        // Act & Assert
        var act = () => new ExperienceTransaction(Guid.Empty, 50, ExperienceSource.Purchase, 1);
        act.Should().Throw<ArgumentException>().WithMessage("*memberId*");
    }

    [Theory]
    [InlineData(1)]
    [InlineData(2)]
    [InlineData(3)]
    [InlineData(4)]
    [InlineData(5)]
    [InlineData(6)]
    [InlineData(7)]
    public void ExperienceSource_ShouldHaveValidIds(int sourceId)
    {
        // Act
        var source = ExperienceSource.FromValue<ExperienceSource>(sourceId);

        // Assert
        source.Should().NotBeNull();
        source.Id.Should().Be(sourceId);
    }

    [Fact]
    public void ExperienceSource_Purchase_ShouldHaveCorrectValues()
    {
        // Assert
        ExperienceSource.Purchase.Id.Should().Be(1);
        ExperienceSource.Purchase.Name.Should().Be("Purchase");
    }

    [Fact]
    public void ExperienceSource_Referral_ShouldHaveCorrectValues()
    {
        // Assert
        ExperienceSource.Referral.Id.Should().Be(2);
        ExperienceSource.Referral.Name.Should().Be("Referral");
    }

    [Fact]
    public void ExperienceSource_Activity_ShouldHaveCorrectValues()
    {
        // Assert
        ExperienceSource.Activity.Id.Should().Be(3);
        ExperienceSource.Activity.Name.Should().Be("Activity");
    }

    [Fact]
    public void ExperienceSource_Promotion_ShouldHaveCorrectValues()
    {
        // Assert
        ExperienceSource.Promotion.Id.Should().Be(4);
        ExperienceSource.Promotion.Name.Should().Be("Promotion");
    }

    [Fact]
    public void ExperienceSource_Review_ShouldHaveCorrectValues()
    {
        // Assert
        ExperienceSource.Review.Id.Should().Be(5);
        ExperienceSource.Review.Name.Should().Be("Review");
    }

    [Fact]
    public void ExperienceSource_CheckIn_ShouldHaveCorrectValues()
    {
        // Assert
        ExperienceSource.CheckIn.Id.Should().Be(6);
        ExperienceSource.CheckIn.Name.Should().Be("CheckIn");
    }

    [Fact]
    public void ExperienceSource_Admin_ShouldHaveCorrectValues()
    {
        // Assert
        ExperienceSource.Admin.Id.Should().Be(7);
        ExperienceSource.Admin.Name.Should().Be("Admin");
    }

    [Fact]
    public void CreatedAt_ShouldBeSetAutomatically()
    {
        // Arrange
        var before = DateTime.UtcNow.AddSeconds(-1);

        // Act
        var transaction = new ExperienceTransaction(Guid.NewGuid(), 50, ExperienceSource.Purchase, 1);

        // Assert
        transaction.CreatedAt.Should().BeAfter(before);
        transaction.CreatedAt.Should().BeBefore(DateTime.UtcNow.AddSeconds(1));
    }

    [Fact]
    public void SetSource_ShouldUpdateSource()
    {
        // Arrange
        var transaction = new ExperienceTransaction(Guid.NewGuid(), 50, ExperienceSource.Purchase, 1);

        // Act
        transaction.SetSource(ExperienceSource.Admin);

        // Assert
        transaction.Source.Should().Be(ExperienceSource.Admin);
    }
}
