using System;
using System.Collections.Specialized;
using System.Linq;
using System.Web;
using System.Web.Caching;
using System.Web.Mvc;
using Hangfire;
using LeafWeb.Core.Entities;
using LeafWeb.Core.Utility;
using LeafWeb.WebCms.Models;
using LeafWeb.WebCms.Services;
using LeafWeb.WebCms.Services.PiscalQueue;
using Umbraco.Web.Mvc;

namespace LeafWeb.WebCms.Controllers
{
	[MemberAuthorize]
	public class QueueController : BaseController
	{
		private const int TimeSamples = 40;

		public ActionResult Index(string query)
		{
			var resultItems =
				DataService.GetLeafInputsOrdered() ;

			// search functionality
			if (!string.IsNullOrEmpty(query))
			{
				foreach (var piece in query.Split(' ').Select(p => p.Trim()))
				{
					resultItems =
						from li in resultItems
						where li.Name.Contains(piece)
						  || li.Identifier.Contains(piece)
						  || li.SiteId.Contains(piece)
						select li;
				}
			}

			var timeInProgressEstimater = TimeInProgressEstimater();

			var serviceDescription = ServiceDescription();
			
			var queueViewModel = new QueueViewModel
			{
				Items = resultItems, ServerDescription = serviceDescription, Query = query,
				TimeInProgressEstimater = timeInProgressEstimater
			};

			return View(queueViewModel);
		}

		private TimeInProgressEstimater TimeInProgressEstimater()
		{
			var estimater = HttpRuntime.Cache["TimeInProgressEstimater"];
			if (estimater == null)
			{
				// completed leaf input for computing runtime statistics
				var completedLeafInput = DataService.GetLeafInputRecentlyCompleted(TimeSamples);
				estimater = new TimeInProgressEstimater(completedLeafInput);
				HttpRuntime.Cache.Insert("TimeInProgressEstimater", estimater, null, DateTime.Now.AddHours(12), Cache.NoSlidingExpiration);
			}

			return (TimeInProgressEstimater)estimater;
		}

		public ActionResult LeafInputStatistics()
		{
			var data =
				from li in DataService.GetLeafInputRecentlyCompleted(TimeSamples)
				select $"{li.InputFiles.Count}, {li.TimeInProgress.TotalSeconds}";
			return Content(string.Join("<br />", data));
		}

		public ActionResult Search(string query)
		{
			var nameValueCollection = new NameValueCollection {{"query", query}};
			return RedirectToUmbracoPage(LeafWebPageIds.ManageQueue, nameValueCollection);
		}

		private static string ServiceDescription()
		{
			string serviceDescription;
			try
			{
				serviceDescription = new PiscalService().ServiceDescription;
			}
			catch (Exception)
			{
				serviceDescription = "Exception while initializing";
			}
			return serviceDescription;
		}

		public ActionResult Details(int id)
		{
			var leafInput = DataService.GetLeafInput(id);

			if (leafInput == null)
			{
				SetStatusMessage($"LeafInput '${id}' not found, may have been deleted?");
				RedirectToUmbracoPage(LeafWebPageIds.ManageQueue);
			}

			var viewModel = new LeafInputDetails(leafInput);
			return View(viewModel);
		}

		public ActionResult DownloadInput(int id)
		{
			return GetInputZip(id);
		}

		public ActionResult DownloadOutputToUser(int id)
		{
			return GetOutputZip(id, LeafOutputFileType.ToUser);
		}

		public ActionResult DownloadOutputNotToUser(int id)
		{
			return GetOutputZip(id, LeafOutputFileType.NotToUser);
		}

		public ActionResult DownloadOutputCleanedInput(int id)
		{
			return GetOutputZip(id, LeafOutputFileType.CleanedInput);
		}

	    private ActionResult GetOutputZip(int id, LeafOutputFileType type)
	    {
			var leafInput = DataService.GetLeafInput(id);

			if (leafInput == null)
				return View("DownloadNotFound");

			var zip = leafInput.GetOutputFileZip(type);

			var filename = $"{leafInput.Identifier.FilterValidFilename()}_{type}.zip";

			return new FileContentResult(zip, "application/zip") { FileDownloadName = filename };
		}

	    private ActionResult GetInputZip(int id)
	    {
			var leafInput = DataService.GetLeafInput(id);

			if (leafInput == null)
				return View("DownloadNotFound");

			var zip = leafInput.GetInputFileZip();

			var filename = $"{leafInput.Identifier.FilterValidFilename()}_Input.zip";

			return new FileContentResult(zip, "application/zip") { FileDownloadName = filename };
		}

		[ActionLog]
		public ActionResult Delete(int id)
		{
			var leafInput = DataService.GetLeafInput(id);

			if (leafInput == null)
			{
				SetStatusMessage($"LeafInput '${id}' not found, perhaps it is already deleted?");
				return RedirectToUmbracoPage(LeafWebPageIds.ManageQueue);
			}

			// don't allow currently running LeafInput to be deleted
			if (leafInput.IsInProgress)
			{
				SetStatusMessage($"LeafInput '{leafInput.Identifier}' is currently running!", StatusType.Error);
				return RedirectToCurrentUmbracoUrl();
			}

			DataService.DeleteLeafInput(leafInput);

			SetStatusMessage($"LeafInput '{leafInput.Identifier}' deleted", StatusType.Success);
			return RedirectToUmbracoPage(LeafWebPageIds.ManageQueue);
		}

		[ActionLog]
		public ActionResult Cancel(int id)
		{
			var leafInput = DataService.GetLeafInput(id);

			if (leafInput == null)
			{
				SetStatusMessage($"LeafInput '${id}' not found, may have been deleted?");
				return RedirectToUmbracoPage(LeafWebPageIds.ManageQueue);
			}

			var cancelPendingSuccess = new PiscalQueueManager().CancelPending(id);

			if (cancelPendingSuccess)
			{
				SetStatusMessage($"Cancelling LeafInput '{leafInput.Identifier}'", StatusType.Success);
			}
			else
			{
				// don't allow to be cancelled if it isn't currently running
				SetStatusMessage($"Couldn't cancel '{leafInput.Identifier}', is it currently running?", StatusType.Error);
			}
			return RedirectToCurrentUmbracoUrl();
		}

		[ActionLog]
		public ActionResult SendUserDownloadLink(int id)
	    {
			var leafInput = DataService.GetLeafInput(id);
			if (leafInput == null)
			{
				SetStatusMessage($"LeafInput '${id}' not found, may have been deleted?");
			}
			else if (!leafInput.IsComplete)
			{
				SetStatusMessage($"LeafInput '{leafInput.Identifier}' is not complete!", StatusType.Error);
			}
			else
			{
				var leafInputId = leafInput.Id;
				BackgroundJob.Enqueue<EmailNotificationService>(e => e.SendLeafWebComplete(leafInputId));
				SetStatusMessage($"LeafInput '{leafInput.Identifier}' download link sent", StatusType.Success);
			}

			return RedirectToCurrentUmbracoUrl();
	    }

		[ActionLog]
		public ActionResult Priority(int id, Priority priority)
	    {
			var leafInput = DataService.GetLeafInput(id);
			if (leafInput == null)
			{
				SetStatusMessage($"LeafInput '${id}' not found, may have been deleted?");
			}
			else if (!leafInput.IsPending)
			{
				SetStatusMessage($"LeafInput '{leafInput.Identifier}' is no longer pending");
			}
			else
			{
				leafInput.PendingPriority = priority;
				DataService.UpdateLeafInput(leafInput);
				SetStatusMessage($"LeafInput '{leafInput.Identifier}' priority set to '{leafInput.PendingPriority}'", StatusType.Success);
			}

			return RedirectToCurrentUmbracoUrl();
	    }

		[ActionLog]
		public ActionResult SendUserChartLink(int id)
	    {
		    throw new System.NotImplementedException();
	    }
	}
}