namespace Kit.Helpers.Log
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;

    public class OperationResult
    {
        public string Title { get; set; }
        public int Level { get; set; }
        public int Count { get; set; }
        public TimeSpan Elapsed { get; set; }
        public OperationResult()
        {
            Title = string.Empty;
        }
    }

    public interface IOperationLogger
    {
        void Log(string operation, int level, Action? action);
        IEnumerable<OperationResult> GetOperationResults();
        string GetOperationResultsAsText();
    }

    public class EmptyOperationLogger : IOperationLogger
    {
        public IEnumerable<OperationResult> GetOperationResults()
        {
            return new List<OperationResult>();
        }
        public string GetOperationResultsAsText()
        {
            return "";
        }
        public void Log(string operation, int level, Action? action)
        {
            if (action != null) action();
        }
    }

    public class OperationLogger : IOperationLogger
    {
        private readonly IDictionary<string, OperationResult> _operationResults;

        public OperationLogger() 
        {
            _operationResults = new Dictionary<string, OperationResult>();
        }

        public static IOperationLogger Empty { get { return new EmptyOperationLogger(); } }

        public void Log(string operation, int level, Action? action)
        {
            var stopwatch = new Stopwatch();

            try
            {
                stopwatch.Start();
                if (action != null) action();
            }
            finally
            {
                stopwatch.Stop();

                OperationResult operationResult = _operationResults.GetByKey(operation);
                if (operationResult == null)
                {
                    operationResult = new OperationResult { Title = operation, Count = 0, Level = level, Elapsed = new TimeSpan() };
                    _operationResults.Add(operation, operationResult);
                }
                operationResult.Count++;
                operationResult.Elapsed += stopwatch.Elapsed;
            }
        }

        public IEnumerable<OperationResult> GetOperationResults()
        {
            return _operationResults.Values;
        }

        public string GetOperationResultsAsText()
        {
            string result = "";
            foreach (var operationResult in _operationResults)
            {
                result += operationResult.Value.Title + Environment.NewLine;
            }
            return result;
        }
    }
}