using BarContracts.BindingModels;
using BarContracts.BusinessLogicContracts;
using BarContracts.StoragesContracts;
using BarDataModels.Models;
using Microsoft.Extensions.Logging;
using System.IO.Compression;
using System.Reflection;
using System.Runtime.Serialization.Json;

namespace BarBusinessLogic.BusinessLogics
{
	public class BackUpLogic : IBackUpLogic
	{
		private readonly ILogger _logger;
		private readonly IBackUpInfo _backUpInfo;
		
		public BackUpLogic(ILogger<BackUpLogic> Logger, IBackUpInfo BackUpInfo)
		{
			_logger = Logger;
			_backUpInfo = BackUpInfo;
		}
		
		public void CreateBackUp(BackUpSaveBindingModel Model)
		{
			if (_backUpInfo == null)
				return;

			try
			{
				_logger.LogDebug("Clear folder");
				var DirInfo = new DirectoryInfo(Model.FolderName);
				if (DirInfo.Exists)
				{
					foreach (var File in DirInfo.GetFiles())
					{
						File.Delete();
					}
				}
				
				_logger.LogDebug("Delete archive");
				string FileName = $"{Model.FolderName}.zip";
				if (File.Exists(FileName))
				{
					File.Delete(FileName);
				}

				_logger.LogDebug("Get assembly");
				var TypeIId = typeof(IId);
				var Assembly = TypeIId.Assembly;
				if (Assembly == null)
				{
					throw new ArgumentNullException("Сборка не найдена", nameof(Assembly));
				}
				
				var Types = Assembly.GetTypes();
				var Method = GetType().GetMethod("SaveToFile", BindingFlags.NonPublic | BindingFlags.Instance);
				
				_logger.LogDebug("Found {count} types", Types.Length);
				
				foreach (var Type in Types)
				{
					if (Type.IsInterface && Type.GetInterface(TypeIId.Name) != null)
					{
						var ModelType = _backUpInfo.GetTypeByModelInterface(Type.Name);
						if (ModelType == null)
						{
							throw new InvalidOperationException($"Не найден класс - модель для { Type.Name }");
					    }
						
						_logger.LogDebug("Call SaveToFile method for {name} Type", Type.Name);
						Method?.MakeGenericMethod(ModelType).Invoke(this, new object[] { Model.FolderName });
					}
				}
				
				_logger.LogDebug("Create zip and remove folder");
				ZipFile.CreateFromDirectory(Model.FolderName, FileName);
				DirInfo.Delete(true);
			}
			catch (Exception)
			{
				throw;
			}
		}
		
		private void SaveToFile<T>(string FolderName) where T : class, new()
		{
			var Records = _backUpInfo.GetList<T>();
			if (Records == null)
			{
				_logger.LogWarning("{type} type get null list", typeof(T).Name);
				return;
			}
			
			var JsonFormatter = new DataContractJsonSerializer(typeof(List<T>));
			using var fs = new FileStream(string.Format("{0}/{1}.json", FolderName, typeof(T).Name), FileMode.OpenOrCreate);
			
			JsonFormatter.WriteObject(fs, Records);
		}
	}
}
