namespace MissionService.UnitTests.Domain;

using FluentAssertions;
using MissionService.Domain.AggregatesModel.MissionAggregate;
using Xunit;

/// <summary>
/// EN: Tests for Mission aggregate root invariants and state transitions.
/// VI: Kiểm thử các quy tắc bất biến và chuyển đổi trạng thái của Mission aggregate root.
/// </summary>
public class MissionAggregateTests
{
    #region Factory Helpers
    
    private static Mission CreateValidMission(
        string code = "TEST_MISSION",
        MissionStatus? initialStatus = null)
    {
        var mission = new Mission(
            code: code,
            titleEn: "Test Mission",
            titleVi: "Mission Kiểm Thử",
            type: MissionType.CheckIn,
            category: MissionCategory.Daily,
            reward: MissionReward.Create(100, 5, 50, null),
            frequency: FrequencyType.Daily,
            maxCompletions: 1,
            startDate: DateTime.UtcNow.AddDays(-1),
            endDate: DateTime.UtcNow.AddDays(30),
            priority: 1);
            
        return mission;
    }
    
    #endregion
    
    #region Constructor Tests
    
    [Fact]
    public void Constructor_ValidParams_CreatesDraftMission()
    {
        // Arrange & Act
        var mission = CreateValidMission();
        
        // Assert
        mission.Code.Should().Be("TEST_MISSION");
        mission.TitleEn.Should().Be("Test Mission");
        mission.TitleVi.Should().Be("Mission Kiểm Thử");
        mission.Status.Should().Be(MissionStatus.Draft);
        mission.Rules.Should().BeEmpty();
    }
    
    [Theory]
    [InlineData(null)]
    [InlineData("")]
    [InlineData("   ")]
    public void Constructor_InvalidCode_ThrowsArgumentException(string? invalidCode)
    {
        // Arrange & Act
        var act = () => new Mission(
            code: invalidCode!,
            titleEn: "Test",
            titleVi: "Test",
            type: MissionType.CheckIn,
            category: MissionCategory.Daily,
            reward: MissionReward.Create(100),
            frequency: FrequencyType.Daily,
            maxCompletions: 1,
            startDate: DateTime.UtcNow);
        
        // Assert
        act.Should().Throw<ArgumentException>()
            .WithMessage("*Mission code is required*");
    }
    
    [Fact]
    public void Constructor_ZeroMaxCompletions_ThrowsArgumentException()
    {
        // Arrange & Act
        var act = () => new Mission(
            code: "TEST",
            titleEn: "Test",
            titleVi: "Test",
            type: MissionType.CheckIn,
            category: MissionCategory.Daily,
            reward: MissionReward.Create(100),
            frequency: FrequencyType.Daily,
            maxCompletions: 0,  // Invalid!
            startDate: DateTime.UtcNow);
        
        // Assert
        act.Should().Throw<ArgumentException>()
            .WithMessage("*Max completions must be at least 1*");
    }
    
    #endregion
    
    #region Status Transition Tests
    
    [Fact]
    public void Activate_DraftMission_ChangesToActive()
    {
        // Arrange
        var mission = CreateValidMission();
        mission.Status.Should().Be(MissionStatus.Draft);
        
        // Act
        mission.Activate();
        
        // Assert
        mission.Status.Should().Be(MissionStatus.Active);
    }
    
    [Fact]
    public void Activate_PausedMission_ChangesToActive()
    {
        // Arrange
        var mission = CreateValidMission();
        mission.Activate();
        mission.Pause();
        mission.Status.Should().Be(MissionStatus.Paused);
        
        // Act
        mission.Activate();
        
        // Assert
        mission.Status.Should().Be(MissionStatus.Active);
    }
    
    [Fact]
    public void Activate_ActiveMission_ThrowsInvalidOperationException()
    {
        // Arrange
        var mission = CreateValidMission();
        mission.Activate();
        
        // Act & Assert
        var act = () => mission.Activate();
        act.Should().Throw<InvalidOperationException>()
            .WithMessage("*Can only activate draft or paused missions*");
    }
    
    [Fact]
    public void Pause_ActiveMission_ChangesToPaused()
    {
        // Arrange
        var mission = CreateValidMission();
        mission.Activate();
        
        // Act
        mission.Pause();
        
        // Assert
        mission.Status.Should().Be(MissionStatus.Paused);
    }
    
    [Fact]
    public void Pause_DraftMission_ThrowsInvalidOperationException()
    {
        // Arrange
        var mission = CreateValidMission();
        
        // Act & Assert
        var act = () => mission.Pause();
        act.Should().Throw<InvalidOperationException>()
            .WithMessage("*Can only pause active missions*");
    }
    
    [Fact]
    public void Archive_AnyStatus_ChangesToArchived()
    {
        // Arrange
        var mission = CreateValidMission();
        
        // Act
        mission.Archive();
        
        // Assert
        mission.Status.Should().Be(MissionStatus.Archived);
    }
    
    #endregion
    
    #region IsAvailable Tests
    
    [Fact]
    public void IsAvailable_ActiveWithinDateRange_ReturnsTrue()
    {
        // Arrange
        var mission = CreateValidMission();
        mission.Activate();
        
        // Act
        var result = mission.IsAvailable();
        
        // Assert
        result.Should().BeTrue();
    }
    
    [Fact]
    public void IsAvailable_DraftStatus_ReturnsFalse()
    {
        // Arrange
        var mission = CreateValidMission();
        
        // Act
        var result = mission.IsAvailable();
        
        // Assert
        result.Should().BeFalse();
    }
    
    [Fact]
    public void IsAvailable_BeforeStartDate_ReturnsFalse()
    {
        // Arrange
        var mission = new Mission(
            code: "FUTURE",
            titleEn: "Future Mission",
            titleVi: "Mission Tương Lai",
            type: MissionType.CheckIn,
            category: MissionCategory.Daily,
            reward: MissionReward.Create(100),
            frequency: FrequencyType.Daily,
            maxCompletions: 1,
            startDate: DateTime.UtcNow.AddDays(10));  // Future start
        mission.Activate();
        
        // Act
        var result = mission.IsAvailable();
        
        // Assert
        result.Should().BeFalse();
    }
    
    #endregion
    
    #region AddRule Tests
    
    [Fact]
    public void AddRule_ValidRule_AddsToCollection()
    {
        // Arrange
        var mission = CreateValidMission();
        var rule = new MissionRule(
            "MinLevel",
            ">=",
            "5");
        
        // Act
        mission.AddRule(rule);
        
        // Assert
        mission.Rules.Should().HaveCount(1);
        mission.Rules.Should().Contain(rule);
    }
    
    [Fact]
    public void AddRule_NullRule_ThrowsArgumentNullException()
    {
        // Arrange
        var mission = CreateValidMission();
        
        // Act & Assert
        var act = () => mission.AddRule(null!);
        act.Should().Throw<ArgumentNullException>();
    }
    
    #endregion
    
    #region UpdateDetails Tests
    
    [Fact]
    public void UpdateDetails_ValidParams_UpdatesProperties()
    {
        // Arrange
        var mission = CreateValidMission();
        
        // Act
        mission.UpdateDetails(
            titleEn: "Updated Title",
            titleVi: "Tiêu Đề Mới",
            descriptionEn: "New description",
            descriptionVi: "Mô tả mới",
            priority: 10);
        
        // Assert
        mission.TitleEn.Should().Be("Updated Title");
        mission.TitleVi.Should().Be("Tiêu Đề Mới");
        mission.DescriptionEn.Should().Be("New description");
        mission.DescriptionVi.Should().Be("Mô tả mới");
        mission.Priority.Should().Be(10);
    }
    
    #endregion
}
