
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xMessageService\Constants\ConfigurationNodeNames.cs

namespace xMessageService.Constants {
    public partial struct ConfigurationNodeNames {
        public const string MESSAGE_NODE_NAME = "MessageConfiguration";
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xMessageService\Constants\xMessageServiceConstants.cs

namespace xMessageService.Constants {
    public struct xMessageServiceConstants {
        public const string DEFAULT_EMPTY_PROVIDER = "EMPTY";
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xMessageService\DI\XDIHelperExtension.cs

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using xCommons.Extensions;
using xMessageService.Constants;
using xMessageService.Interfaces;
using xMessageService.Models;
using xMessageService.Providers;

namespace xMessageService.DI {
    public static partial class XDIHelperExtension {
        /// <summary>
        /// Retrieve XMessage Configuration from App Settings 
        /// </summary>
        /// <param name="config"></param>
        /// <returns></returns>
        public static XMessageConfiguration GetXMessageConfiguration (this IConfiguration config) {
            //
            var xMessageConfigSection = config.GetSection (ConfigurationNodeNames.MESSAGE_NODE_NAME);
            var xMessageConfiguration = xMessageConfigSection.Get<XMessageConfiguration> ();

            //
            var defaultMailConfiguration = new Dictionary<string, XMailConfiguration> {
                    ["EMPTY"] =
                    new XMailConfiguration {
                    Title = xMessageServiceConstants.DEFAULT_EMPTY_PROVIDER,
                    Host = "",
                    Port = 25,
                    EnableSsl = false,
                    Username = "",
                    Password = ""
                    }
                };

            //
            var defaultSmsConfiguration = new Dictionary<string, XSmsConfiguration> {
                    ["EMPTY"] =
                    new XSmsConfiguration {
                    ServiceUrl = "",
                    Username = "",
                    Password = "",
                    LineNumber = "",
                    UserApiKey = "",
                    SecretKey = "",
                    }
                };

            //
            if (xMessageConfiguration.IsNull ()) {
                //
                xMessageConfiguration = new XMessageConfiguration {
                    DefaultSMSProvider = xMessageServiceConstants.DEFAULT_EMPTY_PROVIDER,
                    DefaultMailProvider = xMessageServiceConstants.DEFAULT_EMPTY_PROVIDER,
                    MailConfigurations = defaultMailConfiguration,
                    SmsConfigurations = defaultSmsConfiguration
                };

                //
                // Warn Message is Default Configuration ...
                Console.WriteLine ($"IMPORTANT: xMessageService Configuration is Default, so the Service can't works properly ...");
            }

            //
            // Handle Default Mail Provider ...
            if (xMessageConfiguration.DefaultMailProvider.IsNullOrEmpty ()) {
                //
                if (xMessageConfiguration.IsNull () ||
                    //
                    xMessageConfiguration.MailConfigurations.IsNull () ||
                    xMessageConfiguration.MailConfigurations.Count == 0) {
                    //
                    Console.WriteLine ("There is no defined Mail Provider Configurations ...");
                    xMessageConfiguration.DefaultMailProvider = xMessageServiceConstants.DEFAULT_EMPTY_PROVIDER;
                }

                //
                if (xMessageConfiguration.DefaultMailProvider == xMessageServiceConstants.DEFAULT_EMPTY_PROVIDER) {
                    xMessageConfiguration.MailConfigurations = defaultMailConfiguration;
                } else {
                    xMessageConfiguration.DefaultMailProvider = xMessageConfiguration.MailConfigurations.Keys.First ();
                }
            }

            //
            // Handle Default SMS Provider ...
            if (xMessageConfiguration.DefaultSMSProvider.IsNullOrEmpty ()) {
                //
                if (xMessageConfiguration.IsNull () ||
                    xMessageConfiguration.SmsConfigurations.IsNull () ||
                    xMessageConfiguration.SmsConfigurations.Count == 0) {
                    //
                    Console.WriteLine ("There is no defined SMS Provider Configurations ...");
                    xMessageConfiguration.DefaultSMSProvider = xMessageServiceConstants.DEFAULT_EMPTY_PROVIDER;
                }

                //
                if (xMessageConfiguration.DefaultSMSProvider == xMessageServiceConstants.DEFAULT_EMPTY_PROVIDER) {
                    xMessageConfiguration.SmsConfigurations = defaultSmsConfiguration;
                } else {
                    xMessageConfiguration.DefaultSMSProvider = xMessageConfiguration.SmsConfigurations.Keys.First ();
                }
            }

            //
            return xMessageConfiguration;
        }

        /// <summary>
        /// Register XMessage Service 
        /// </summary>
        /// <param name="services"></param>
        /// <param name="config"></param>
        public static void AddXMessageService (this IServiceCollection services, IConfiguration config) {
            //
            var xMessageConfiguration = config.GetXMessageConfiguration ();
            services.AddSingleton<XMessageConfiguration> (xMessageConfiguration);

            //
            // Register SMS Service ...
            var xSmsService = new XSmsService (
                xMessageConfiguration.DefaultSMSProvider,
                xMessageConfiguration.SmsConfigurations
            );
            services.AddSingleton<IXSmsService> (xSmsService);

            //
            // Register Mail Service ...
            var xMailService = new XMailService (
                xMessageConfiguration.DefaultMailProvider,
                xMessageConfiguration.MailConfigurations
            );
            services.AddSingleton<IXMailService> (xMailService);

            //
            // Register MEssage Provider ...
            services.AddSingleton<IXMessageProvider, XMessageProvider> ();
        }
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xMessageService\Interfaces\IXMailService.cs

using System.Threading.Tasks;
using xMessageService.Models;

namespace xMessageService.Interfaces {
    public partial interface IXMailService {
        Task SendMailAsync (
            XMessage message,
            string provider = null
        );
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xMessageService\Interfaces\IXMessageProvider.cs

using System;
using System.Threading.Tasks;
using xMessageService.Models;

namespace xMessageService.Interfaces {
    public partial interface IXMessageProvider {
        bool IsReady (
            bool? checkMailService = false,
            bool? checkSmsService = false
        );

        Task SendMailAsync (
            XMessage message,
            string provider = null,
            bool throwException = true,
            Exception exception = null
        );

        Task SendSmsAsync (
            XMessage message,
            string provider = null,
            bool throwException = true,
            Exception exception = null
        );
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xMessageService\Interfaces\IXSmsService.cs

using System.Threading.Tasks;
using xMessageService.Models;

namespace xMessageService.Interfaces {
    public partial interface IXSmsService {
        Task SendSmsAsync (
            XMessage message,
            string provider = null
        );
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xMessageService\Models\XMailConfiguration.cs

namespace xMessageService.Models {
    public partial class XMailConfiguration {
        public string Title { get; set; }
        public string Host { get; set; }
        public int Port { get; set; }
        public bool EnableSsl { get; set; }
        public string Username { get; set; }
        public string Password { get; set; }
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xMessageService\Models\XMessage.cs

using System.Collections.Generic;
using xModels.Base;

namespace xMessageService.Models {
    public partial class XMessage : XBaseDto {
        public HashSet<string> Recievers { get; set; } = new HashSet<string> ();
        public string Message { get; set; }
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xMessageService\Models\XMessageConfiguration.cs

using System.Collections.Generic;

namespace xMessageService.Models {
    public partial class XMessageConfiguration {
        public string DefaultSMSProvider { get; set; }
        public string DefaultMailProvider { get; set; }
        public IDictionary<string, XMailConfiguration> MailConfigurations { get; set; }
        public IDictionary<string, XSmsConfiguration> SmsConfigurations { get; set; }
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xMessageService\Models\XSmsConfiguration.cs

namespace xMessageService.Models {
    public partial class XSmsConfiguration {
        public string ServiceUrl { get; set; }
        public string Username { get; set; }
        public string Password { get; set; }
        public string LineNumber { get; set; }
        public string UserApiKey { get; set; }
        public string SecretKey { get; set; }
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xMessageService\Providers\XMailService.cs

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Mail;
using System.Threading.Tasks;
using xCommons.Extensions;
using xExceptions.Constants;
using xMessageService.Interfaces;
using xMessageService.Models;

namespace xMessageService.Providers {
    public partial class XMailService : IXMailService {
        private SmtpClient smtpClient;
        private readonly string defaultProvider;
        private readonly IDictionary<string, XMailConfiguration> configurations;

        public XMailService (
            string defaultProvider,
            IDictionary<string, XMailConfiguration> configurations
        ) {
            this.defaultProvider = defaultProvider;
            this.configurations = configurations;

            //
            // Get instance of SMTP Client ...
            PrepareSmtpClient ();
        }

        public Task SendMailAsync (
            XMessage message,
            string provider = null
        ) {
            //
            // Run Send Mail Asynchronous ...
            return Task.Run (() => {
                SendMail (message, provider);
            });
        }

        #region Private ...
        /// <summary>
        /// Validate and Retrieve Provider Configuration for Service
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        private XMailConfiguration GetConfiguration (string provider = null) {
            //
            if (provider.IsNullOrEmpty ()) {
                provider = defaultProvider;
            }

            //
            if (!configurations.Keys.Contains (provider)) {
                XException.MessageServiceInitialFailed.Throw ();
            }

            //
            return configurations[provider];
        }

        /// <summary>
        /// Prepare SMTP Client by Using Specified/Default Provider
        /// </summary>
        /// <param name="provider"></param>
        private void PrepareSmtpClient (string provider = null) {
            //
            var config = GetConfiguration (provider);
            if (config.IsNull()) {
                return;
            }

            //
            smtpClient = new SmtpClient () {
                Host = config.Host,
                Port = config.Port,
                EnableSsl = config.EnableSsl,
                UseDefaultCredentials = false,
                Credentials = new NetworkCredential (
                config.Username,
                config.Password)
            };
        }

        /// <summary>
        /// Prepare Mail Message With Specified/Default Provider
        /// </summary>
        /// <param name="message"></param>
        /// <param name="provider"></param>
        /// <returns></returns>
        private MailMessage PrepareMailMessage (
            XMessage message,
            string provider = null
        ) {
            //
            if (message == null ||
                message.Message.IsNullOrEmpty () ||
                message.Recievers.Count == 0) {
                XException.InvalidMessage.Throw ();
            }

            //
            var config = GetConfiguration (provider);
            var mailMessage = new MailMessage () {
                From = new MailAddress (config.Username),
                Subject = config.Title,
                Body = message.Message
            };

            //
            foreach (var reciever in message.Recievers) {
                mailMessage.To.Add (reciever);
            }

            //
            return mailMessage;
        }

        /// <summary>
        /// Send Mail Using Specified/Default Provider
        /// </summary>
        /// <param name="message"></param>
        /// <param name="provider"></param>
        private void SendMail (
            XMessage message,
            string provider = null
        ) {
            //
            if (smtpClient.IsNull()) {
                //
                Console.WriteLine ($"SMTP Error: MessageServiceInitialFailed ...");
                XException.MessageServiceInitialFailed.Throw ();
            }

            //
            var mailMessage = PrepareMailMessage (message, provider);

            //
            try {
                smtpClient.Send (mailMessage);
            } catch (Exception ex) {
                //
                Console.WriteLine ($"SMTP Error: {ex.Message}");
                XException.MessageServiceInitialFailed.Throw ();
            }
        }
        #endregion        
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xMessageService\Providers\XMessageProvider.cs

using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using xCommons.Extensions;
using xExceptions.Constants;
using xMessageService.Interfaces;
using xMessageService.Models;

namespace xMessageService.Providers {
    public partial class XMessageProvider : IXMessageProvider {
        private readonly XMessageConfiguration configuration;
        private readonly ILogger<XMessageProvider> logger;
        private readonly IXSmsService smsService;
        private readonly IXMailService mailService;

        public XMessageProvider (
            XMessageConfiguration configuration,
            ILogger<XMessageProvider> logger,
            IXSmsService smsService,
            IXMailService mailService
        ) {
            this.configuration = configuration;
            this.logger = logger;
            this.smsService = smsService;
            this.mailService = mailService;
        }

        /// <summary>
        /// Send a Mail Message
        /// </summary>
        /// <param name="message"></param>
        /// <param name="provider"></param>
        /// <param name="throwException"></param>
        /// <param name="exception"></param>
        /// <returns></returns>
        public async Task SendMailAsync (
            XMessage message,
            string provider = null,
            bool throwException = true,
            Exception exception = null
        ) {
            //
            if (exception.IsNull ()) {
                exception = XException.ActionFailed.ToException ();
            }

            //
            try {
                await mailService.SendMailAsync (message, provider);
            } catch (Exception ex) {
                //
                logger.LogError ($"Exeption: {ex.Message}");

                //
                if (throwException) {
                    throw exception;
                }
            }
        }

        /// <summary>
        /// Send SMS Message 
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public async Task SendSmsAsync (
            XMessage message,
            string provider = null,
            bool throwException = true,
            Exception exception = null
        ) {
            //
            if (exception.IsNull ()) {
                exception = XException.ActionFailed.ToException ();
            }

            //
            try {
                await smsService.SendSmsAsync (message, provider);
            } catch {
                if (throwException) {
                    throw exception;
                }
            }
        }

        /// <summary>
        /// Check Message Provider is Ready or not
        /// </summary>
        /// <param name="checkMailService"></param>
        /// <param name="checkSmsService"></param>
        /// <returns></returns>
        public bool IsReady (
            bool? checkMailService = false,
            bool? checkSmsService = false
        ) {
            //
            var result = true;

            //
            // Check Mail Service ...
            if (checkMailService.HasValue &&
                checkMailService.GetValueOrDefault ()) {
                result = result && mailService != null;
            }

            //
            // Check Sms Service ...
            if (checkSmsService.HasValue &&
                checkSmsService.GetValueOrDefault ()) {
                result = result && smsService != null;
            }

            //
            return result;
        }
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xMessageService\Providers\XSmsService.cs

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using PhoneNumbers;
using RestSharp;
using xCommons.Extensions;
using xExceptions.Constants;
using xMessageService.Interfaces;
using xMessageService.Models;

namespace xMessageService.Providers {
    public partial class XSmsService : IXSmsService {
        private string serviceUrl;
        private readonly string defaultProvider;
        private readonly IDictionary<string, XSmsConfiguration> configurations;

        public XSmsService (
            string defaultProvider,
            IDictionary<string, XSmsConfiguration> configurations
        ) {
            this.defaultProvider = defaultProvider;
            this.configurations = configurations;

            //
            PrepareServiceUrl ();
        }

        public Task SendSmsAsync (
            XMessage message,
            string provider = null
        ) {
            //
            // Run Send SMS Asynchronous ...
            return Task.Run (() => {
                SendSMS (message, provider);
            });
        }

        #region Private ...
        /// <summary>
        /// Prepare Service Url for Specified/Default Provider
        /// </summary>
        /// <param name="provider"></param>
        private void PrepareServiceUrl (string provider = null) {
            //
            if (provider.IsNullOrEmpty ()) {
                provider = defaultProvider;
            }

            //
            var config = GetConfiguration (provider);
            if (config.IsNull ()) {
                return;
            }

            //
            serviceUrl = config.ServiceUrl;
            serviceUrl += "&username=" + config.Username + "&password=" + config.Password + "&";
        }

        /// <summary>
        /// Prepare Service url for Integrating XMessage by 
        /// using Specified/Default Provider Configurations
        /// </summary>
        /// <param name="message"></param>
        /// <param name="provider"></param>
        private void PrepareSmsMessage (
            XMessage message,
            string provider = null
        ) {
            //
            if (message == null ||
                message.Message.IsNullOrEmpty () ||
                message.Recievers.Count == 0) {
                XException.InvalidMessage.Throw ();
            }

            //
            // Validating Mobile Numbers ...
            var phoneNumberUtil = PhoneNumbers.PhoneNumberUtil.GetInstance ();
            var recieversList = "";

            //
            PrepareServiceUrl (provider);

            //
            foreach (var reciever in message.Recievers) {
                try {
                    //
                    var mPhoneNumber = phoneNumberUtil.Parse (reciever, null);
                    if (phoneNumberUtil.IsValidNumber (mPhoneNumber)) {
                        //
                        // Format Phone Numbers to the '+989120000000' pattern ...
                        var recieverPhone = phoneNumberUtil.Format (mPhoneNumber, PhoneNumberFormat.E164);
                        if (recieversList.Length > 0) {
                            recieversList += ",";
                        }
                        recieversList += reciever;
                    }
                } catch { }
            }

            //
            var config = GetConfiguration ();

            //
            // Preparing All Content and Configurations for Sending Messages ...
            serviceUrl += "to=" +
                recieversList +
                "&message=" +
                message.Message +
                "&from=" +
                config.LineNumber +
                "&flash=" +
                false;
        }

        /// <summary>
        /// Send a Message as SMS by Specified/Default Provider
        /// </summary>
        /// <param name="message"></param>
        /// <param name="provider"></param>
        private void SendSMS (
            XMessage message,
            string provider = null
        ) {
            //
            if (serviceUrl.IsNullOrEmpty ()) {
                //
                Console.WriteLine ($"SMS Error: MessageServiceInitialFailed ...");
                XException.MessageServiceInitialFailed.Throw ();
            }

            //
            try {
                //
                // preparing Service Url based on message data ...
                PrepareSmsMessage (message, provider);

                //
                // Implementing Service Calling Using RestSharp Library ...
                // We Select RestSharp because it supports Sync/Async Calls ...
                var client = new RestClient (serviceUrl);
                var request = new RestRequest (Method.POST);

                //
                // Send Request ...
                var response = client.Execute (request);
            } catch (Exception ex) {
                Console.WriteLine ($"SMS Error: {ex.Message}");
                XException.MessageServiceInitialFailed.Throw ();
            }
        }

        /// <summary>
        /// Validate and Retrieve Provider Configuration for Service
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        private XSmsConfiguration GetConfiguration (string provider = null) {
            //
            if (
                provider.IsNullOrEmpty () ||
                provider.ToNormalString () == "empty"
            ) {
                //
                provider = defaultProvider;
                return null;
            }

            //
            if (!configurations.Keys.Contains (provider)) {
                XException.MessageServiceInitialFailed.Throw ();
            }

            //
            return configurations[provider];
        }
        #endregion        
    }
}
