using log4net;
using log4net.Appender;
using log4net.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net.Repository;
using log4net.Repository.Hierarchy;

namespace skyscraper8.Skyscraper.Plugins
{
	internal class PluginAppender : AppenderSkeleton
	{
		private PluginAppenderEx _finalOutput;
		protected override void Append(LoggingEvent loggingEvent)
		{
			object? messageObject = loggingEvent.MessageObject;
			if (messageObject == null)
				messageObject = "";
			PluginLogLevel mappedLevel = MapLevel(loggingEvent.Level);
			DateTime mappedTime = DateTime.Now;
			string mappedLoggerName = loggingEvent.LoggerName;
			string mappedMessage = messageObject.ToString();
			_finalOutput.Log(mappedTime, mappedLevel, mappedLoggerName, mappedMessage);
		}

		private PluginLogLevel MapLevel(Level loggingEventLevel)
		{
			if (loggingEventLevel.Equals(Level.Debug))
				return PluginLogLevel.Debug;
			else if (loggingEventLevel.Equals(Level.All))
				return PluginLogLevel.All;
			else if (loggingEventLevel.Equals(Level.Error))
				return PluginLogLevel.Error;
			else if (loggingEventLevel.Equals(Level.Fatal))
				return PluginLogLevel.Fatal;
			else if (loggingEventLevel.Equals(Level.Info))
				return PluginLogLevel.Info;
			else if (loggingEventLevel.Equals(Level.Warn))
				return PluginLogLevel.Warn;
			else if (loggingEventLevel.Equals(Level.Off))
				return PluginLogLevel.Off;
			else
				throw new NotImplementedException(loggingEventLevel.ToString());
		}

		internal PluginAppender(PluginAppenderEx pex)
		{
			this._finalOutput = pex;
		}
	}

	public abstract class PluginAppenderEx
	{
		private static readonly ILog logger = LogManager.GetLogger(typeof(PluginAppenderEx));
		private PluginAppender appender;

		public abstract void Log(DateTime mappedTime, PluginLogLevel mappedLevel, string? mappedLoggerName, string? mappedMessage);

		private bool registered;
		public void Register()
		{
			if (registered)
				throw new PluginsException("Appender was already registered.");

			logger.DebugFormat("Registering a log appender plugin: {0}",this.GetType().Name);

			appender = new PluginAppender(this);

			ILoggerRepository loggerRepository = log4net.LogManager.GetRepository();
			Hierarchy hierarchy = (log4net.Repository.Hierarchy.Hierarchy)loggerRepository;
			hierarchy.Root.AddAppender(appender);

			registered = true;
		}
	}
}
