using System;
using System.Data.Entity.Validation;
using System.Linq;
using LeafWeb.Core.Entities;
using LeafWeb.Core.Parsers;
using LeafWeb.WebCms.App_Start;

namespace LeafWeb.WebCms.Services.PiscalQueue
{
	public class FinishComplete : PiscalQueueWorker
	{
		protected override void DoWorkInternal(LeafInput leafInput)
		{
			Logger.DebugFormat("LeafInput: {0}, RetrieveOutputFiles", leafInput.Id);

			var leafOutputFiles = PiscalService.RetrieveOutputFiles(leafInput).ToList();

			Logger.DebugFormat("LeafInput: {0}, RetrieveOutputFiles saving output files", leafInput.Id);

			foreach (var outputFile in leafOutputFiles)
			{
				if (leafInput.OutputFiles.All(file => file.Filename != outputFile.Filename))
				{
					DataService.AddLeafOutputFile(outputFile);

					// parse cleaned input file data
					if (outputFile.FileType == LeafOutputFileType.CleanedInput)
						AddLeafInputData(outputFile, leafInput);
				}
				else
					Logger.WarnFormat("LeafInput: {0}, RetrieveOutputFiles duplicate file name: {1}", leafInput.Id, outputFile.Filename);
			}

			Logger.InfoFormat("LeafInput: {0}, RetrieveOutputFiles output files: {1}", leafInput.Id,
				string.Join(", ", leafOutputFiles.Select(o => o.Filename)));

			Logger.DebugFormat("LeafInput: {0}, Set Complete", leafInput.Id);
			DataService.SetLeafInputStatus(leafInput, LeafInputStatusType.Complete, 
				"Emailing notification to user and cleaning up files on Piscal",
				$"Email: \'{leafInput.Email}\'{Environment.NewLine}" + 
				$"Output files: {leafOutputFiles.Count}");

			BackgroundJobEnqueueRetry<EmailNotificationService>(email => email.SendLeafWebComplete(leafInput.Id));

			Logger.InfoFormat("LeafInput: {0}, Cleanup", leafInput.Id);
			PiscalService.Cleanup(leafInput);

			HangfireStartup.TriggerPiscalProcessQueue();
		}

		private void AddLeafInputData(LeafOutputFile outputFile, LeafInput leafInput)
		{
			try
			{
				var parser = new LeafInputCsvParser(outputFile.FileContents.Contents);
				var data = parser.Parse();
				LeafInputCleaner.Clean(data);
				data.LeafInput = leafInput;
				data.LeafOutputFile = outputFile;
				leafInput.LeafInputData.Add(data);
				DataService.UpdateLeafInput(leafInput);
			}
			catch (DbEntityValidationException ex)
			{
				var valErrors =
					string.Join("",
						ex.EntityValidationErrors.Select(
							e => string.Join(Environment.NewLine,
								e.ValidationErrors.Select(v => $"{v.PropertyName} - {v.ErrorMessage}"))));
				Logger.Error($"LeafInput: {leafInput.Id}, while parsing CleanedInput file: {outputFile.Filename}"+
				             $"{Environment.NewLine}Validation Errors:{valErrors}");
			}
			catch (Exception e)
			{
				Logger.Error($"LeafInput: {leafInput.Id}, while parsing CleanedInput file: {outputFile.Filename}", e);
			}
		}
	}
}