using Azure; using Azure.Communication; using Azure.Communication.CallAutomation; using Azure.Communication.Identity; using Azure.Communication.Rooms; using EnotaryoPH.Data; using EnotaryoPH.Data.Entities; namespace EnotaryoPH.Web.Common.Services { public class ConferenceSheduleService : IConferenceSheduleService { private readonly NotaryoDBContext _dbContext; private readonly CommunicationIdentityClient _communicationIdentityClient; private readonly RoomsClient _roomsClient; private readonly CallAutomationClient _callAutomationClient; private readonly IConfiguration _configuration; public ConferenceSheduleService(NotaryoDBContext dbContext, CommunicationIdentityClient communicationIdentityClient, RoomsClient roomsClient, CallAutomationClient callAutomationClient, IConfiguration configuration) { _dbContext = dbContext; _communicationIdentityClient = communicationIdentityClient; _roomsClient = roomsClient; _callAutomationClient = callAutomationClient; _configuration = configuration; } public async Task GetOrCreateScheduleIDAsync(Guid transaction_UID) { if (transaction_UID == Guid.Empty) { return Guid.Empty; } var transactionEntity = _dbContext.Transactions .Include(t => t.TransactionSignatories) .FirstOrDefault(t => t.Transaction_UID == transaction_UID); if (transactionEntity == null) { return Guid.Empty; } var existingSchedule = _dbContext.LawyerVideoConferenceSchedules.FirstOrDefault(sched => sched.TransactionID == transactionEntity.TransactionID); if (existingSchedule != null) { return existingSchedule.LawyerVideoConferenceSchedule_UID; } var schedule_UID = Guid.Empty; var isReadyForVideoCall = transactionEntity.TransactionSignatories.All(signatory => signatory.Status == nameof(SignatoryStatus.FaceMatch)); var isAcceptedByLawyer = transactionEntity.Status == nameof(TransactionState.Accepted) && transactionEntity.LawyerID > 0; if (isReadyForVideoCall && isAcceptedByLawyer) { var schedule = _dbContext.LawyerVideoConferenceSchedules.FirstOrDefault(sched => sched.TransactionID == transactionEntity.TransactionID); if (schedule == null) { var participants = transactionEntity.TransactionSignatories.ConvertAll(signatory => new LawyerVideoConferenceParticipant { CreatedOn = DateTime.UtcNow, Status = nameof(VideoConferenceStatus.New), LawyerVideoConferenceParticipant_UID = Guid.CreateVersion7(DateTime.UtcNow), ParticipantID = signatory.UserID, }); participants.Add(new LawyerVideoConferenceParticipant { CreatedOn = DateTime.UtcNow, Status = nameof(VideoConferenceStatus.New), LawyerVideoConferenceParticipant_UID = Guid.CreateVersion7(DateTime.UtcNow), ParticipantID = transactionEntity.PrincipalID, }); schedule = new LawyerVideoConferenceSchedule { LawyerVideoConferenceSchedule_UID = Guid.CreateVersion7(DateTime.UtcNow), CreatedOn = DateTime.UtcNow, LawyerID = transactionEntity.LawyerID.GetValueOrDefault(), TransactionID = transactionEntity.TransactionID, MeetingDate = DateTime.UtcNow, Status = nameof(VideoConferenceStatus.New), }; var roomParticipants = new List(); foreach (var participant in participants) { var attendee = await _communicationIdentityClient.CreateUserAsync(); participant.MeetingRoomTokenID = await GetTokenResponseAsync(attendee); participant.MeetingRoomUserID = attendee.Value.Id; roomParticipants.Add(new RoomParticipant(attendee) { Role = ParticipantRole.Attendee }); } var presenter = await _communicationIdentityClient.CreateUserAsync(); schedule.MeetingRoomTokenID = await GetTokenResponseAsync(presenter); schedule.MeetingRoomUserID = presenter.Value.Id; roomParticipants.Add(new RoomParticipant(presenter) { Role = ParticipantRole.Presenter }); CommunicationRoom room = await _roomsClient.CreateRoomAsync(DateTime.Now, DateTime.Now.AddHours(2), roomParticipants); schedule.MeetingRoomID = room.Id; schedule.LawyerVideoConferenceParticipants = participants.ToList(); if (schedule.LawyerVideoConferenceScheduleID == 0) { _dbContext.Add(schedule); } else { _dbContext.Update(schedule); } _dbContext.SaveChanges(); schedule_UID = schedule.LawyerVideoConferenceSchedule_UID; } } return schedule_UID; } public async Task StartRecordingAsync(Guid transaction_UID, string serverCallID) { var transactionEntity = _dbContext.Transactions .FirstOrDefault(t => t.Transaction_UID == transaction_UID) ?? throw new ArgumentException("Transaction not found."); var existingSchedule = _dbContext.LawyerVideoConferenceSchedules.FirstOrDefault(sched => sched.TransactionID == transactionEntity.TransactionID) ?? throw new ArgumentException("Schedule not found."); if (string.IsNullOrEmpty(existingSchedule.ServerCallID) && string.IsNullOrEmpty(serverCallID)) { throw new ArgumentException("ServerCallID is not set for this transaction."); } if (!string.IsNullOrEmpty(existingSchedule.RecordingID)) { return; } if (!string.IsNullOrEmpty(serverCallID)) { existingSchedule.ServerCallID = serverCallID; } CallLocator callLocator = new ServerCallLocator(existingSchedule.ServerCallID); var uri = _configuration.GetValue("UriRecordingBloblContainer") ?? string.Empty; var recordingResult = await _callAutomationClient .GetCallRecording().StartAsync(new StartRecordingOptions(callLocator) { RecordingStorage = RecordingStorage.CreateAzureBlobContainerRecordingStorage(new Uri(uri)) }); existingSchedule.RecordingID = recordingResult.Value.RecordingId; _dbContext.Update(existingSchedule); _dbContext.SaveChanges(); } public async Task StopRecordingAsync(Guid transaction_UID) { var transactionEntity = _dbContext.Transactions .FirstOrDefault(t => t.Transaction_UID == transaction_UID) ?? throw new ArgumentException("Transaction not found."); var existingSchedule = _dbContext.LawyerVideoConferenceSchedules.FirstOrDefault(sched => sched.TransactionID == transactionEntity.TransactionID) ?? throw new ArgumentException("Schedule not found."); if (string.IsNullOrEmpty(existingSchedule.ServerCallID)) { throw new ArgumentException("ServerCallID is not set for this transaction."); } if (string.IsNullOrEmpty(existingSchedule.RecordingID)) { throw new ArgumentException("Recording ID is not set for this transaction."); } await _callAutomationClient.GetCallRecording().StopAsync(existingSchedule.RecordingID); } private async Task GetTokenResponseAsync(Response user) { var tokenResponse = await _communicationIdentityClient.GetTokenAsync(user, new[] { CommunicationTokenScope.VoIP }); return tokenResponse.Value.Token; } } }