using GozareshgirProgramManager.Application._Common.Interfaces; using GozareshgirProgramManager.Application._Common.Models; using GozareshgirProgramManager.Domain._Common; using GozareshgirProgramManager.Domain._Common.Exceptions; using GozareshgirProgramManager.Domain.ProjectAgg.Enums; using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.ChangeStatusSection; public record ChangeStatusSectionCommand(Guid SectionId, TaskSectionStatus Status) : IBaseCommand; public class ChangeStatusSectionCommandHandler : IBaseCommandHandler { private readonly IUnitOfWork _unitOfWork; private readonly ITaskSectionRepository _taskSectionRepository; private readonly IAuthHelper _authHelper; public ChangeStatusSectionCommandHandler(ITaskSectionRepository taskSectionRepository, IUnitOfWork unitOfWork, IAuthHelper authHelper) { _taskSectionRepository = taskSectionRepository; _unitOfWork = unitOfWork; _authHelper = authHelper; } public async Task Handle(ChangeStatusSectionCommand request, CancellationToken cancellationToken) { // استفاده از متد مخصوص که Activities رو load می‌کنه var section = await _taskSectionRepository.GetByIdWithActivitiesAsync(request.SectionId, cancellationToken); if (section == null) return OperationResult.NotFound("بخش مورد نظر یافت نشد"); if (section.Status == request.Status) return OperationResult.Success(); long currentUser = _authHelper.GetCurrentUserId() ?? throw new UnAuthorizedException("کاربر احراز هویت نشده است"); // Validate state transitions var validationResult = ValidateStateTransition(section.Status, request.Status); if (!validationResult.IsSuccess) return validationResult; // Handle state machine logic if (section.Status == TaskSectionStatus.InProgress) { // Coming FROM InProgress: Stop the active activity section.StopWork(request.Status); } else if (request.Status == TaskSectionStatus.InProgress) { // Going TO InProgress: Check if section has remaining time, then start work if (!section.HasRemainingTime()) return OperationResult.ValidationError("زمان این بخش به پایان رسیده است"); if (await _taskSectionRepository.HasUserAnyInProgressSectionAsync(section.CurrentAssignedUserId, cancellationToken)) { return OperationResult.ValidationError("کاربر مورد نظر در حال حاضر بخش دیگری را در وضعیت 'درحال انجام' دارد"); } section.StartWork(); } else { // All other transitions: Just update status section.UpdateStatus(request.Status); } await _unitOfWork.SaveChangesAsync(cancellationToken); return OperationResult.Success(); } /// /// Validates state transitions based on business rules: /// - ReadyToStart: شروع نشده - Initial state only, cannot return to it once left /// - InProgress: درحال انجام - Can transition from ReadyToStart, can go to Incomplete or Completed /// - Incomplete: نیمه کاره - Can come from InProgress or other states /// - Completed: اتمام رسیده - Can come from InProgress or other states /// private OperationResult ValidateStateTransition(TaskSectionStatus currentStatus, TaskSectionStatus targetStatus) { // Cannot transition to ReadyToStart once the section has been started if (targetStatus == TaskSectionStatus.ReadyToStart) return OperationResult.ValidationError("بخش نمی‌تواند به وضعیت 'آماده برای شروع' تغییر کند"); // From ReadyToStart, can only go to InProgress if (currentStatus == TaskSectionStatus.ReadyToStart && targetStatus != TaskSectionStatus.InProgress) return OperationResult.ValidationError("از وضعیت 'آماده برای شروع' فقط می‌توان به 'درحال انجام' رفت"); // Valid transitions matrix var validTransitions = new Dictionary> { { TaskSectionStatus.ReadyToStart, [TaskSectionStatus.InProgress] }, { TaskSectionStatus.InProgress, [TaskSectionStatus.Incomplete, TaskSectionStatus.PendingForCompletion] }, { TaskSectionStatus.Incomplete, [TaskSectionStatus.InProgress, TaskSectionStatus.PendingForCompletion] }, { TaskSectionStatus.PendingForCompletion, [TaskSectionStatus.InProgress, TaskSectionStatus.Incomplete] }, // Can return to InProgress or Incomplete { TaskSectionStatus.NotAssigned, [TaskSectionStatus.InProgress, TaskSectionStatus.ReadyToStart] } }; if (!validTransitions.TryGetValue(currentStatus, out var allowedTargets)) return OperationResult.ValidationError($"وضعیت فعلی '{currentStatus}' نامعتبر است"); if (!allowedTargets.Contains(targetStatus)) return OperationResult.ValidationError( $"نمی‌توان از وضعیت '{currentStatus}' به '{targetStatus}' رفت"); return OperationResult.Success(); } }