/// <summary>
 /// Mark an email as read.
 /// </summary>
 /// <param name="id">Message id.</param>
 /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
 public async Task MarkMessageAsReadAsync(string id)
 {
     try
     {
         await this._graphClient.Me.Messages[id].Request().Select("IsRead").UpdateAsync(new Message {
             IsRead = true
         });
     }
     catch (ServiceException ex)
     {
         throw GraphClient.HandleGraphAPIException(ex);
     }
 }
        /// <summary>
        /// Update a specified message.
        /// </summary>
        /// <param name="updatedMessage">updatedMessage.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public async Task <Message> UpdateMessage(Message updatedMessage)
        {
            try
            {
                // Update the message.
                var result = await this._graphClient.Me.Messages[updatedMessage.Id].Request().UpdateAsync(updatedMessage);

                return(result);
            }
            catch (ServiceException ex)
            {
                throw GraphClient.HandleGraphAPIException(ex);
            }
        }
        /// <summary>
        /// Reply to a specified message.
        /// </summary>
        /// <param name="id">The Id of message to reply.</param>
        /// <param name="text">The rely message body.</param>
        /// <returns>Completed Task.</returns>
        public async Task <List <Message> > ReplyToMessageAsync(string id, string text)
        {
            List <Message> items = new List <Message>();

            try
            {
                // Reply to the message.
                await this._graphClient.Me.Messages[id].ReplyAll(text).Request().PostAsync();
            }
            catch (ServiceException ex)
            {
                throw GraphClient.HandleGraphAPIException(ex);
            }

            // This operation doesn't return anything.
            return(items);
        }
        /// <summary>
        /// GetContactAsync.
        /// </summary>
        /// <param name="name">name.</param>
        /// <returns>Task contains List of Contacts.</returns>
        private async Task <List <Contact> > GetMSContactsAsync(string name)
        {
            List <Contact> items = new List <Contact>();

            var optionList   = new List <QueryOption>();
            var filterString = $"startswith(displayName, '{name}') or startswith(givenName,'{name}') or startswith(surname,'{name}')";

            optionList.Add(new QueryOption("$filter", filterString));

            // Get the current user's profile.
            IUserContactsCollectionPage contacts = null;

            try
            {
                contacts = await this._graphClient.Me.Contacts.Request(optionList).GetAsync();
            }
            catch (ServiceException ex)
            {
                throw GraphClient.HandleGraphAPIException(ex);
            }

            if (contacts?.Count > 0)
            {
                foreach (Contact contact in contacts)
                {
                    // Filter out conference rooms.
                    string displayName = contact.DisplayName ?? string.Empty;
                    if (!displayName.StartsWith("Conf Room"))
                    {
                        // Get user properties.
                        items.Add(contact);
                    }

                    if (items.Count >= 10)
                    {
                        break;
                    }
                }
            }

            return(items);
        }
        /// <summary>
        /// GetUsersAsync.
        /// </summary>
        /// <param name="name">name.</param>
        /// <returns>Task contains List of Users.</returns>
        private async Task <List <User> > GetMSUserAsync(string name)
        {
            var items        = new List <User>();
            var optionList   = new List <QueryOption>();
            var filterString = $"startswith(displayName, '{name}') or startswith(givenName,'{name}') or startswith(surname,'{name}') or startswith(mail,'{name}') or startswith(userPrincipalName,'{name}')";

            optionList.Add(new QueryOption("$filter", filterString));

            // Get the current user's profile.
            IGraphServiceUsersCollectionPage users = null;

            try
            {
                users = await _graphClient.Users.Request(optionList).GetAsync();
            }
            catch (ServiceException ex)
            {
                throw GraphClient.HandleGraphAPIException(ex);
            }

            if (users?.Count > 0)
            {
                foreach (var user in users)
                {
                    // Filter out conference rooms.
                    var displayName = user.DisplayName ?? string.Empty;
                    if (!displayName.StartsWith("Conf Room"))
                    {
                        // Get user properties.
                        items.Add(user);
                    }

                    if (items.Count >= 10)
                    {
                        break;
                    }
                }
            }

            return(items);
        }
        /// <summary>
        /// Send an email message.
        /// </summary>
        /// <param name="content">Email Body.</param>
        /// <param name="subject">Eamil Subject.</param>
        /// <param name="recipients">List of recipient.</param>
        /// <returns>Completed Task.</returns>
        public async Task SendMessageAsync(string content, string subject, List <Recipient> recipients)
        {
            // todo: I don't know why but recipient list need to be create again to avoid 400 error
            List <Recipient> re = new List <Recipient>();

            foreach (var recipient in recipients)
            {
                re.Add(new Recipient
                {
                    EmailAddress = new EmailAddress
                    {
                        Address = recipient.EmailAddress.Address,
                    },
                });
            }

            // Create the message.
            Message email = new Message
            {
                Body = new ItemBody
                {
                    Content     = content,
                    ContentType = BodyType.Html,
                },
                Subject      = subject,
                ToRecipients = re,
            };

            // Send the message.
            try
            {
                await this._graphClient.Me.SendMail(email, true).Request().PostAsync();
            }
            catch (ServiceException ex)
            {
                throw GraphClient.HandleGraphAPIException(ex);
            }

            // This operation doesn't return anything.
        }
        public async Task <PersonModel> GetMeAsync()
        {
            try
            {
                var me = await _graphClient.Me.Request().GetAsync();

                if (me != null)
                {
                    var url = await GetMSUserPhotoUrlAsyc(me.Id);

                    var personMe = new PersonModel(me.ToPerson());
                    personMe.Photo = url;

                    return(personMe);
                }

                return(null);
            }
            catch (ServiceException ex)
            {
                throw GraphClient.HandleGraphAPIException(ex);
            }
        }
        /// <summary>
        /// Get people whose name contains specified word.
        /// </summary>
        /// <param name="name">person name.</param>
        /// <returns>the persons list.</returns>
        private async Task <List <Person> > GetMSPeopleAsync(string name)
        {
            var items        = new List <Person>();
            var optionList   = new List <QueryOption>();
            var filterString = $"\"{name}\"";

            optionList.Add(new QueryOption("$search", filterString));

            // Get the current user's profile.
            IUserPeopleCollectionPage users = null;

            try
            {
                users = await _graphClient.Me.People.Request(optionList).GetAsync();
            }
            catch (ServiceException ex)
            {
                throw GraphClient.HandleGraphAPIException(ex);
            }

            // var users = await _graphClient.Users.Request(optionList).GetAsync();
            if (users?.Count > 0)
            {
                foreach (var user in users)
                {
                    // Filter out conference rooms.
                    var displayName = user.DisplayName ?? string.Empty;
                    if (!displayName.StartsWith("Conf Room"))
                    {
                        // Get user properties.
                        items.Add(user);
                    }
                }
            }

            return(items);
        }
        /// <summary>
        /// Get messages in all the current user's mail folders.
        /// </summary>
        /// <param name="fromTime">search condition, start time.</param>
        /// <param name="toTime">search condition, end time.</param>
        /// <param name="getUnRead">bool flag, if get unread email.</param>
        /// <param name="isImportant">bool flag, if get important email.</param>
        /// <param name="directlyToMe">bool flag, if filter email directly to me.</param>
        /// <param name="fromAddress">search condition, filter email from this address.</param>
        /// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns>
        public async Task <List <Message> > GetMyMessagesAsync(DateTime fromTime, DateTime toTime, bool getUnRead = false, bool isImportant = false, bool directlyToMe = false, string fromAddress = null)
        {
            try
            {
                var optionList   = new List <QueryOption>();
                var filterString = string.Empty;
                if (getUnRead)
                {
                    filterString = this.AppendFilterString(filterString, "isread:false");
                }

                if (isImportant)
                {
                    filterString = this.AppendFilterString(filterString, "importance:high");
                }

                if (directlyToMe)
                {
                    User me = await this._graphClient.Me.Request().GetAsync();

                    var address = me.Mail ?? me.UserPrincipalName;
                    filterString = this.AppendFilterString(filterString, $"to:{address}");
                }

                if (!string.IsNullOrEmpty(fromAddress))
                {
                    filterString = this.AppendFilterString(filterString, $"from:{fromAddress}");
                }

                if (!string.IsNullOrEmpty(filterString))
                {
                    optionList.Add(new QueryOption("$search", $"\"{filterString}\""));
                }

                // skip can't be used with search
                // optionList.Add(new QueryOption("$skip", $"{page}"));

                // some message don't have receiveddatetime. use last modified datetime.
                // optionList.Add(new QueryOption(GraphQueryConstants.Orderby, "lastModifiedDateTime desc"));
                // only get emails from Inbox folder.
                IMailFolderMessagesCollectionPage messages =
                    optionList.Count != 0 ?
                    await this._graphClient.Me.MailFolders.Inbox.Messages.Request(optionList).GetAsync() :
                    await this._graphClient.Me.MailFolders.Inbox.Messages.Request().GetAsync();

                List <Message> result = new List <Message>();

                var done = false;
                while (messages?.Count > 0 && !done)
                {
                    var messagesList = messages?.OrderByDescending(message => message.ReceivedDateTime).ToList();
                    foreach (Message message in messagesList)
                    {
                        var receivedDateTime = message.ReceivedDateTime;
                        if (receivedDateTime > fromTime && receivedDateTime < toTime)
                        {
                            result.Add(message);
                        }
                        else
                        {
                            done = true;
                        }
                    }

                    if (messages.NextPageRequest != null)
                    {
                        messages = await messages.NextPageRequest.GetAsync();
                    }
                    else
                    {
                        done = true;
                    }
                }

                return(result.OrderByDescending(message => message.ReceivedDateTime).ToList());
            }
            catch (ServiceException ex)
            {
                throw GraphClient.HandleGraphAPIException(ex);
            }
        }