using Centron.BusinessLogic.Tapi; using Centron.Interfaces; using Microsoft.Graph.Models.CallRecords; namespace Centron.Tests.BL.Tapi; public class PhoneCallBLTest { private const int CentronSystemEmployeeI3D = 999; [Fact] public void CreateSyncedPhoneCallsKeepsOneRowPerParticipant() { var organizer = CreateEmployeeCaller(1, "Organizer"); var employeeParticipant = CreateEmployeeCaller(2, "Participant"); var externalParticipant1 = CreateExternalCaller("external1@example.com"); var externalParticipant2 = CreateExternalCaller("external2@example.com"); var result = PhoneCallBL.CreateSyncedPhoneCalls( CreateCall(CallType.GroupCall), organizer, [organizer, employeeParticipant, externalParticipant1, externalParticipant2, externalParticipant2], [1, 2], CentronSystemEmployeeI3D); Assert.Equal(3, result.Count); Assert.All(result, phoneCall => { Assert.Equal(organizer.ObjektI3D, phoneCall.CreatedBy); Assert.Equal(organizer.Name, phoneCall.CreatorName); Assert.True(phoneCall.IsGroupCall); }); Assert.Equal( [employeeParticipant.Number, externalParticipant1.Number, externalParticipant2.Number], result.Select(x => x.CallerNumber).OrderBy(x => x)); } [Fact] public void CreateSyncedPhoneCallsKeepsPeerToPeerCallAsSingleRow() { var organizer = CreateEmployeeCaller(1, "Organizer"); var participant = CreateEmployeeCaller(2, "Participant"); var phoneCall = Assert.Single(PhoneCallBL.CreateSyncedPhoneCalls( CreateCall(CallType.PeerToPeer), organizer, [organizer, participant], [1, 2], CentronSystemEmployeeI3D)); Assert.Equal(1, phoneCall.CreatedBy); Assert.Equal(2, phoneCall.OwnerI3D); Assert.Equal(participant.Number, phoneCall.CallerNumber); Assert.True(phoneCall.WasOutgoing); Assert.True(phoneCall.WasInternalCall); Assert.False(phoneCall.IsGroupCall); } [Fact] public void CreateSyncedPhoneCallsKeepsRowWhenOnlyParticipantIsSynchronized() { var organizer = CreateEmployeeCaller(1, "Organizer"); var participant = CreateEmployeeCaller(2, "Participant"); var phoneCall = Assert.Single(PhoneCallBL.CreateSyncedPhoneCalls( CreateCall(CallType.PeerToPeer), organizer, [participant], [2], CentronSystemEmployeeI3D)); Assert.Equal(1, phoneCall.CreatedBy); Assert.Equal(2, phoneCall.OwnerI3D); } [Fact] public void CreateSyncedPhoneCallsIgnoresCallsWithoutSynchronizedEmployee() { var organizer = CreateEmployeeCaller(1, "Organizer"); var participant = CreateEmployeeCaller(2, "Participant"); var result = PhoneCallBL.CreateSyncedPhoneCalls( CreateCall(CallType.PeerToPeer), organizer, [participant], [3], CentronSystemEmployeeI3D); Assert.Empty(result); } [Fact] public void CreateSyncedPhoneCallsKeepsExternalParticipantsOfRelevantGroupCall() { var organizer = CreateExternalCaller("external-organizer@example.com"); var participant1 = CreateEmployeeCaller(1, "Participant 1"); var participant2 = CreateEmployeeCaller(2, "Participant 2"); var externalParticipant = CreateExternalCaller("external-participant@example.com"); var result = PhoneCallBL.CreateSyncedPhoneCalls( CreateCall(CallType.GroupCall), organizer, [participant1, participant2, externalParticipant], [1, 2], CentronSystemEmployeeI3D); Assert.Equal(3, result.Count); Assert.Equal([1, 2, CentronSystemEmployeeI3D], result.Select(x => x.CreatedBy).OrderBy(x => x)); Assert.All(result, phoneCall => Assert.Equal(organizer.Number, phoneCall.CallerNumber)); } [Fact] public void PairComparisonAllowsParticipantAddedAfterInitialImport() { var organizer = CreateEmployeeCaller(1, "Organizer"); var initialParticipant = CreateEmployeeCaller(2, "Initial Participant"); var laterParticipant = CreateEmployeeCaller(3, "Later Participant"); var call = CreateCall(CallType.GroupCall); var existingPhoneCall = Assert.Single(PhoneCallBL.CreateSyncedPhoneCalls( call, organizer, [initialParticipant], [1, 2, 3], CentronSystemEmployeeI3D)); var refreshedPhoneCalls = PhoneCallBL.CreateSyncedPhoneCalls( call, organizer, [initialParticipant, laterParticipant], [1, 2, 3], CentronSystemEmployeeI3D); Assert.True(PhoneCallBL.IsSameSyncedPhoneCall(existingPhoneCall, refreshedPhoneCalls.Single(x => x.OwnerI3D == 2))); Assert.False(PhoneCallBL.IsSameSyncedPhoneCall(existingPhoneCall, refreshedPhoneCalls.Single(x => x.OwnerI3D == 3))); } [Fact] public void UpdateSyncedPhoneCallRefreshesCallAfterParticipantWasAdded() { var organizer = CreateEmployeeCaller(1, "Organizer"); var initialParticipant = CreateEmployeeCaller(2, "Initial Participant"); var laterParticipant = CreateEmployeeCaller(3, "Later Participant"); var initialCall = CreateCall(CallType.PeerToPeer); initialCall.EndDateTime = initialCall.StartDateTime.GetValueOrDefault().AddMinutes(4); var existingPhoneCall = Assert.Single(PhoneCallBL.CreateSyncedPhoneCalls( initialCall, organizer, [initialParticipant], [1, 2, 3], CentronSystemEmployeeI3D)); var refreshedCall = CreateCall(CallType.GroupCall); refreshedCall.Id = initialCall.Id; refreshedCall.EndDateTime = refreshedCall.StartDateTime.GetValueOrDefault().AddMinutes(15); var refreshedPhoneCall = PhoneCallBL.CreateSyncedPhoneCalls( refreshedCall, organizer, [initialParticipant, laterParticipant], [1, 2, 3], CentronSystemEmployeeI3D) .Single(x => x.OwnerI3D == initialParticipant.ObjektI3D); var wasUpdated = PhoneCallBL.UpdateSyncedPhoneCall(existingPhoneCall, refreshedPhoneCall); Assert.True(wasUpdated); Assert.Equal(refreshedCall.EndDateTime.Value.LocalDateTime, existingPhoneCall.EndTime); Assert.Equal(15 * 60, existingPhoneCall.DurationInSeconds); Assert.True(existingPhoneCall.IsGroupCall); Assert.False(PhoneCallBL.UpdateSyncedPhoneCall(existingPhoneCall, refreshedPhoneCall)); } private static CallRecord CreateCall(CallType callType) => new() { Id = Guid.NewGuid().ToString(), Type = callType, StartDateTime = new DateTimeOffset(2026, 7, 13, 10, 0, 0, TimeSpan.Zero), EndDateTime = new DateTimeOffset(2026, 7, 13, 11, 0, 0, TimeSpan.Zero) }; private static Caller CreateEmployeeCaller(int employeeI3D, string name) => new() { ObjektI3D = employeeI3D, ObjektArt = CentronObjectKindNumeric.EmployeeClass, Name = name, Number = $"employee{employeeI3D}@example.com" }; private static Caller CreateExternalCaller(string number) => new() { ObjektArt = CentronObjectKindNumeric.Unknown, Name = number, Number = number }; }