public async System.Threading.Tasks.Task SignUpRollback([ServiceBusTrigger(Constants.ROLL_BACK_SEAT_RESERVATION, Constants.ALL_MESSAGES_SUBSCRIPTION, Connection = Constants.SERVICE_BUS_CONNECTION_NAME)] SignUpProcessedMessage message, ILogger log)
        {
            log.LogInformation($"[INF-0003] Rollback received: {message}");

            var(courseId, student, _) = message;
            var course = await _coursesServiceProxy.FindAsync(courseId);

            if (course == null)
            {
                log.LogCritical("[CRIT-0001] Course not found.");
                return;
            }

            if (course.Students.Contains(student))
            {
                await _coursesServiceProxy.ReleaseSeat(course, student);

                await _messageProxy.SendToTopic(Constants.NEW_SEAT_AVAILABLE, new NewSeatAvailableMessage(course.Id));

                await _messageProxy.SendToTopic(Constants.SIGN_UP_FINISHED, message);
            }
            else
            {
                // Student already rolledback. No need to process message
                return;
            }
        }
        public async System.Threading.Tasks.Task ProcessAsync([ServiceBusTrigger(Constants.NEW_SIGN_UP_TOPIC, Constants.ALL_MESSAGES_SUBSCRIPTION, Connection = Constants.SERVICE_BUS_CONNECTION_NAME)] NewSignUpMessage message, ILogger log)
        {
            log.LogInformation($"[INF-0001] New sign up received: {message}");

            var(courseId, student) = message;
            var course = await _coursesServiceProxy.FindAsync(courseId);


            if (!course.Students.Contains(student))
            {
                var processedMessage = new SignUpProcessedMessage(courseId, student, Status: SignUpStatus.New);
                var waitListOrder    = await _coursesServiceProxy.ConsumeSeatAvailable(course, student);

                var status = waitListOrder switch
                {
                    0 => SignUpStatus.SeatReserved,
                    > 0 => SignUpStatus.OnWaitList,
                    _ => throw new InvalidOperationException("Unexpected value returned from consume seat available")
                };

                processedMessage = processedMessage with {
                    Status = status
                };

                await _messageProxy.SendToTopic(Constants.SIGN_UP_PROCESSED_TOPIC, processedMessage);
            }
            else
            {
                // Student already on course. No need to process message
                return;
            }
        }
        public async System.Threading.Tasks.Task RunAsync([ServiceBusTrigger(Constants.SIGN_UP_PROCESSED_TOPIC, Constants.ACCEPTED_STUDENTS_MESSAGES, Connection = Constants.SERVICE_BUS_CONNECTION_NAME)] SignUpProcessedMessage message, ILogger log)
        {
            var studentAccepted = message.StudentAccepted;

            if (studentAccepted)
            {
                // Storing messages on cache to process all together
                await _cacheService.StoreOnSet(Constants.SIGN_UP_PROCESSED_TOPIC, message);
            }
        }
        public async System.Threading.Tasks.Task RunAsync([ServiceBusTrigger(Constants.SIGN_UP_FINISHED, Constants.ALL_MESSAGES_SUBSCRIPTION, Connection = Constants.SERVICE_BUS_CONNECTION_NAME)] SignUpProcessedMessage message, ILogger log)
        {
            log.LogInformation($"Sending email for sign up: {message}");

            var(courseId, student, _) = message;
            var course = await _coursesService.FindAsync(courseId);

            if (message.StudentAccepted)
            {
                _emailService.SendEmail(student.Email, ChamaSystemTexts.AcceptedIntoCourseTemplate(course, student));
            }
            else if (message.Status == SignUpStatus.CreditRefused)
            {
                _emailService.SendEmail(student.Email, ChamaSystemTexts.CreditRefusedCourseTemplate(course, student));
            }
            else
            {
                _emailService.SendEmail(student.Email, ChamaSystemTexts.NotAcceptedIntoCourseTemplate(course, student));
            }
        }