using System;
using System.Configuration;
using System.Net;
using System.Net.Mail;
using log4net;
using LeafWeb.Core.DAL;
using LeafWeb.Core.Entities;
using LeafWeb.Core.Utility;
using LeafWeb.WebCms.Models;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Web;
using Umbraco.Web.PublishedCache;
using Umbraco.Web.Security;

namespace LeafWeb.WebCms.Services
{
	public class EmailNotificationService : IDisposable
	{
		private static readonly ILog Logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

		private readonly string _emailFromAddress;

		private const string SuccessSubject = "LeafWeb results";
		private const string ErrorSubject = "LeafWeb processing error";
		private const string SystemErrorSubject = "LeafWeb system error";
		private const string CancelledSubject = "LeafWeb cancelled";
		private const string ContactSubject = "LeafWeb Contact Message";

		/// <summary>
		/// comma separated values
		/// </summary>
		private readonly string _adminEmailAddresses;

		private readonly SmtpClient _smtpClient;

		private readonly DataService _dataService;

		private readonly UrlService _urlService;

		private string FormatSubject(string subject, LeafInput leafInput)
		{
			return subject + $" - '{leafInput.Identifier}'";
		}

		public EmailNotificationService(DataService dataService)
		{
			_dataService = dataService;

			_urlService = new UrlService();

			_smtpClient = new SmtpClient(
				ConfigurationManager.AppSettings["SmtpHost"],
				Convert.ToInt32(ConfigurationManager.AppSettings["SmtpPort"]));

			if (!string.IsNullOrEmpty(ConfigurationManager.AppSettings["SmtpUserName"]))
				_smtpClient.Credentials = new NetworkCredential(
					ConfigurationManager.AppSettings["SmtpUserName"],
					ConfigurationManager.AppSettings["SmtpPassword"]
					);

			_emailFromAddress = ConfigurationManager.AppSettings["EmailFromAddress"];
			_adminEmailAddresses = ConfigurationManager.AppSettings["AdminEmailAddresses"];
		}

		public EmailNotificationService() : this(new DataService())
		{ }

		public void SendLeafWebComplete(int leafInputId)
		{
			var leafInput = _dataService.GetLeafInput(leafInputId);
			if (leafInput.CurrentStatus != LeafInputStatusType.Complete)
			{
				var notComplete = "Attempting to SendLeafWebComplete when status is not complete" +
				              $" for leafInput: {leafInput}, current status: {leafInput.CurrentStatus}";
				Logger.Error(notComplete);
				throw new ArgumentException(notComplete);
			}

			var outputErrorMessage = leafInput.OutputErrorMessage;
			if (outputErrorMessage != null)
				SendLeafWebError(leafInput, outputErrorMessage.FileContents.Contents.GetString());
			else
				SendLeafWebSuccess(leafInput);
		}

		public void SendLeafWebCancelled(int leafInputId)
		{
			var leafInput = _dataService.GetLeafInput(leafInputId);
			if (leafInput.CurrentStatus != LeafInputStatusType.Cancelled)
			{
				var notComplete = "Attempting to SendLeafWebCancelled when status is not complete " +
				              $"for leafInput: {leafInput}, current status: {leafInput.CurrentStatus}";
				Logger.Error(notComplete);
				throw new ArgumentException(notComplete);
			}

			var body = $"Your leaf analysis job, {leafInput.Identifier}, has been cancelled. " +
			           "Contact the administrator with any questions.";

			var message = new MailMessage(_emailFromAddress, leafInput.Email, FormatSubject(CancelledSubject, leafInput), body);
			SendMessage(message);
		}

		public void SendAdministratorMessage(string subject, string body)
		{
			var message = new MailMessage(_emailFromAddress, _adminEmailAddresses, subject, body);
			SendMessage(message);
		}

		private void SendLeafWebSuccess(LeafInput leafInput)
		{
			var body = $"Your leaf analysis job, {leafInput.Identifier}, has completed. ";

			body += FormatWarningMessage(leafInput);

			var downloadLink = true;

			if (downloadLink)
			{
				var downloadUrl = _urlService.GetDownloadUrl(leafInput);

				body += 
					"Download results with the following link:" 
					+ Environment.NewLine + Environment.NewLine 
					+ downloadUrl;

				var message = new MailMessage(_emailFromAddress, leafInput.Email, FormatSubject(SuccessSubject, leafInput), body);
				SendMessage(message);
			}
			//else
			//{
			//	body += "Please see the attached results.";

			//	var message = new MailMessage(_emailFromAddress, leafInput.Email, SuccessSubject, body);

			//	var fileStreams =
			//		(from outputFile in
			//			leafInput.OutputFiles
			//			select Tuple.Create(outputFile, new MemoryStream(outputFile.FileContents.Contents))).ToList();
			//	try
			//	{
			//		foreach (var fileStream in fileStreams)
			//		{
			//			var attachment = new Attachment(fileStream.Item2, fileStream.Item1.Filename);
			//			message.Attachments.Add(attachment);
			//		}

			//		SendMessage(message);
			//	}
			//	finally
			//	{
			//		// can't dispose those memory streams until the message is sent
			//		foreach (var stream in fileStreams.Select(f => f.Item2))
			//		{
			//			stream.Dispose();
			//		}
			//	}
			//}
		}

		private void SendLeafWebError(LeafInput leafInput, string errorMessage)
		{
			var body = $"Your leaf analysis job, {leafInput.Identifier}, encountered the following errors." + Environment.NewLine
			           + Environment.NewLine + Environment.NewLine
			           + errorMessage
					   + Environment.NewLine + Environment.NewLine
					   + "You will need to correct your input and resubmit.";

			body += FormatWarningMessage(leafInput);

			var message = new MailMessage(_emailFromAddress, leafInput.Email, FormatSubject(ErrorSubject, leafInput), body);
			SendMessage(message);
		}

		public void SendLeafWebSystemException(string leafInputIdentifier, string leafInputEmail)
		{
			var body = $"A system error occured while processing your leaf analysis job, {leafInputIdentifier}." + Environment.NewLine
					   + "System administrators have been notified. You will be notified again when the system error "
					   + "has been resolved and your data has been processed.";

			var message = new MailMessage(_emailFromAddress, leafInputEmail, SystemErrorSubject, body);
			SendMessage(message);
		}

		public void SendContactEmail(ContactForm contact)
		{
			var body =
				$"via LeafWeb, {contact.Name} sent the following message from the Contact form." +
				Environment.NewLine + Environment.NewLine +
				"Message" +
				Environment.NewLine + Environment.NewLine +
				"--------" +
				Environment.NewLine + Environment.NewLine +
				contact.Message;

			var message = new MailMessage(_emailFromAddress, _adminEmailAddresses, ContactSubject, body)
			{
				From = new MailAddress(contact.Email, contact.Name)
			};
			SendMessage(message);
		}

        public void SendVerifyMemberEmail(string memberEmail)
        {
            var servicesMemberService = ApplicationContext.Current.Services.MemberService;
            var member = servicesMemberService.GetByEmail(memberEmail);
            var verifyEmailURl = _urlService.GetVerifyEmailURl(member);
            var body = "Please verify your email address with this link " + verifyEmailURl;

            var message = new MailMessage(_emailFromAddress, member.Email, "Verify your email for LeafWeb", body);
            SendMessage(message);
        }

        private string FormatWarningMessage(LeafInput leafInput)
		{
			if (leafInput.OutputWarningMessage != null)
				return Environment.NewLine + Environment.NewLine
					+ "The following warning message was generated."
					+ Environment.NewLine + Environment.NewLine
					+ leafInput.OutputWarningMessage.FileContents.Contents.GetString()
					+ Environment.NewLine;
			return string.Empty;
		}

		private void SendMessage(MailMessage mailMessage)
		{
			try
			{
				Logger.Info($"Email sending to {mailMessage.To}, subject: {mailMessage.Subject}");
				_smtpClient.Send(mailMessage);
			}
			catch (SmtpException ex)
			{
				Logger.Error($"Failed to send mail: {ex.Message}", ex);
			}
		}

		public void Dispose()
		{
			_dataService.Dispose();
		}

    }
}