// Copyright © 2017-2018 Atomic Software, LLC. All Rights Reserved.
// See LICENSE.md for full license information.

using System;
using System.IO;

namespace Atom.Core.Diagnostics
{
    /// <summary>
    /// The <see cref="Log"/> class provides an easy implementation for logging methods,
    /// to trace executing code and gain insight to the application during runtime.
    /// </summary>
    public static class Log
    {
        private static readonly object LogLock = new object();

        public static void Info(string message)
        {
            Info(null, message);
        }

        public static void Info(string file, string message, bool outToConsole = true, bool timeStamp = true)
        {
            AddMessage(MessageSeverity.Info, file, message, outToConsole, timeStamp);
        }

        public static void Warning(string message)
        {
            Warning(null, message);
        }

        public static void Warning(string file, string message, bool outToConsole = true, bool timeStamp = true)
        {
            AddMessage(MessageSeverity.Warning, file, message, outToConsole, timeStamp);
        }

        public static void PerformanceWarning(string message)
        {
            PerformanceWarning(null, message);
        }

        public static void PerformanceWarning(string file, string message, bool outToConsole = true, bool timeStamp = true)
        {
            AddMessage(MessageSeverity.PerformanceWarning, file, message, outToConsole, timeStamp);
        }

        public static void CriticalError(string message)
        {
            CriticalError(null, message);
        }

        public static void CriticalError(string file, string message, bool outToConsole = true, bool timeStamp = true)
        {
            AddMessage(MessageSeverity.CriticalError, file, message, outToConsole, timeStamp);
        }

        private static void AddMessage(MessageSeverity severity, string file, string message, bool outToConsole = true, bool timeStamp = true)
        {
            lock (LogLock)
            {
                if (!string.IsNullOrEmpty(file))
                {
                    try
                    {
                        var FileDirectory = Path.GetDirectoryName(file);

                        if (!string.IsNullOrEmpty(FileDirectory))
                        {
                            Directory.CreateDirectory(FileDirectory);
                        }
                    }
                    catch
                    {
                        // ignored
                    }
                    finally
                    {
                        using (var FileWriter = new StreamWriter($"{file}{(!timeStamp ? "" : DateTime.Now.ToString("yyyyMMddHH"))}.txt", true))
                        {
                            FileWriter.AutoFlush = true;
                            FileWriter.WriteLine($"{(!timeStamp ? "" : DateTime.Now.ToString("T") + " : ")}{message}");
                            FileWriter.Close();
                        }
                    }
                }

                if (outToConsole)
                {
                    Console.ForegroundColor = ConsoleColor.DarkGray;
                    Console.Write($"[{DateTime.Now:yyyy.MM.dd-HH.mm.ss:fff}] ");

                    Console.ForegroundColor = GetLogColor(severity);
                    Console.WriteLine($"{GetSeverityText(severity)}{message}");

                    Console.ResetColor();
                }
            }
        }

        private static ConsoleColor GetLogColor(MessageSeverity severity)
        {
            switch (severity)
            {
                case MessageSeverity.CriticalError:
                    return ConsoleColor.Red;
                case MessageSeverity.PerformanceWarning:
                case MessageSeverity.Warning:
                    return ConsoleColor.Yellow;
                default:
                    return ConsoleColor.DarkGray;
            }
        }

        private static string GetSeverityText(MessageSeverity severity)
        {
            switch (severity)
            {
                case MessageSeverity.CriticalError:
                    return "Critical Error: ";
                case MessageSeverity.PerformanceWarning:
                    return "Performance Warning: ";
                case MessageSeverity.Warning:
                    return "Warning: ";
                default:
                    return "";
            }
        }
    }
}