public async Task <CurrentTimeEntryDto> ClockIn(int patrolId, int userId, DateTime?now = null)
        {
            if (!now.HasValue)
            {
                now = _systemClock.UtcNow.UtcDateTime;
            }
            var existingEntries = await _timeEntryRepository.GetActiveTimeEntries(patrolId, userId);

            //if there are existing entries we don't need to do anything
            if (!existingEntries.Any())
            {
                var result = new CurrentTimeEntryDto();
                var entry  = new TimeEntry()
                {
                    ClockIn  = now.Value,
                    PatrolId = patrolId,
                    UserId   = userId
                };
                await _timeEntryRepository.InsertTimeEntry(entry);

                result.TimeEntry = entry;

                //if the patrol has schedulingenabled, try to find a shift to associate
                var patrol = await _patrolRepository.GetPatrol(patrolId);

                if (patrol.EnableScheduling)
                {
                    //find shifts for the user that occur in the next day
                    //TODO: does this range need to be configurable by patrol?  eg: how early can you allow clocking in?
                    var shifts = await _shiftRepository.GetScheduledShiftAssignments(patrolId, userId, entry.ClockIn, entry.ClockIn + new TimeSpan(1, 0, 0, 0), ShiftStatus.Assigned);

                    shifts = shifts.OrderBy(x => x.StartsAt);
                    if (shifts.Any())
                    {
                        //if there is more than one match, associate the one that starts the earliest
                        var shift          = shifts.First();
                        var scheduledShift = await _shiftRepository.GetScheduledShift(shift.ScheduledShiftId);

                        var timeEntryScheduledShiftAssignment = new TimeEntryScheduledShiftAssignment()
                        {
                            ScheduledShiftAssignmentId = shift.Id,
                            TimeEntryId = entry.Id
                        };
                        await _timeEntryRepository.InsertTimeEntryScheduledShiftAssignment(timeEntryScheduledShiftAssignment);

                        result.TimeEntryScheduledShiftAssignment = timeEntryScheduledShiftAssignment;
                        result.ScheduledShift = scheduledShift;
                        if (scheduledShift.ShiftId.HasValue)
                        {
                            result.Shift = await _shiftRepository.GetShift(scheduledShift.ShiftId.Value);
                        }
                        if (scheduledShift.GroupId.HasValue)
                        {
                            result.Group = await _groupRepository.GetGroup(scheduledShift.GroupId.Value);
                        }
                    }
                }

                return(result);
            }
            else
            {
                var result = new CurrentTimeEntryDto();
                var entry  = existingEntries.Where(x => x.ClockIn < now).OrderBy(x => x.ClockIn).FirstOrDefault();

                var timeEntryScheduledShiftAssignments = await _timeEntryRepository.GetScheduledShiftAssignmentsForTimeEntry(entry.Id);

                if (timeEntryScheduledShiftAssignments.Any())
                {
                    var tessa = timeEntryScheduledShiftAssignments.FirstOrDefault();
                    result.TimeEntryScheduledShiftAssignment = tessa;
                    var assignment = await _shiftRepository.GetScheduledShiftAssignment(tessa.ScheduledShiftAssignmentId);

                    result.ScheduledShift = await _shiftRepository.GetScheduledShift(assignment.ScheduledShiftId);

                    if (result.ScheduledShift.ShiftId.HasValue)
                    {
                        result.Shift = await _shiftRepository.GetShift(result.ScheduledShift.ShiftId.Value);
                    }
                    if (result.ScheduledShift.GroupId.HasValue)
                    {
                        result.Group = await _groupRepository.GetGroup(result.ScheduledShift.GroupId.Value);
                    }
                }

                return(result);
            }
        }