// Copyright (c) Strange Loop Games. All rights reserved.
// See LICENSE file in the project root for full license information.

namespace Eco.Mods.ChatLog
{
    using Eco.Core.Plugins.Interfaces;
    using Eco.Core.Utils;
    using Eco.Gameplay.Players;
    using Eco.Gameplay.Systems.Chat;
    using Eco.Shared.Localization;
    using Eco.Shared.Services;
    using System;
    using System.Collections.Concurrent;
    using Eco.Core.Utils.Logging;
    using PathUtils = Eco.Shared.Utils.PathUtils;
    using Eco.Shared.Utils;

    /// <summary> Logs chat and related information (such as login/logout events) to plain text files for server administration purposes. </summary>
    class ChatLogger : IModKitPlugin, IInitializablePlugin
    {
        const string ChatLogNamePrefix = "Chat";

        readonly ConcurrentDictionary<(string, string), ILogWriter> loggers = new();

        public override string ToString()   => Localizer.DoStr("Chat log");
        public string GetStatus()           => string.Empty;

        public void Initialize(TimedTask timer)
        {
            UserManager.OnNewUserJoined.Add(user => { this.LogLoginEvent(Localizer.DoStr($"--> {user.Name} joined the server.")); });
            UserManager.OnUserLoggedOut.Add(user => { this.LogLoginEvent(Localizer.DoStr($"<-- {user.Name} logged out.")); });
            UserManager.OnUserLoggedIn.Add(user => { this.LogLoginEvent(Localizer.DoStr($"--> {user.Name} logged in.")); });
            ChatManager.MessageSent.Add(this.OnMessageSent);
        }

        // Formats the message and logs it to the relevant log file.
        void OnMessageSent(ChatMessage msg)
        {
            if (msg.Temporary) return;

            string category;
            string name;
            switch (msg.Category)
            {
                case MessageCategory.Chat:
                    category = "Channel";
                    name = msg.Tag.Substring(1); // Remove the #
                    break;

                case MessageCategory.Whisper:
                    category = "Whisper";

                    var recipientName = msg.Tag.Substring(1); // Remove the @
                    var senderName = msg.Sender;

                    // Make sure that the names are always in the same order
                    name = string.Compare(senderName, recipientName, StringComparison.Ordinal) < 0 ? $"{senderName}-{recipientName}" : $"{recipientName}-{senderName}";
                    break;

                default:
                    return;
            }

            // Separate the username from the director character
            this.LogMessage(category, name, $"{msg.Sender}: {msg.Text}");
        }

        void LogLoginEvent(string message)
        {
            this.LogMessage("Login", string.Empty, message);
            this.LogMessage("Channel", "General", message);
        }

        void LogMessage(string category, string name, string message)
        {
            var logger = this.loggers.GetOrAdd((category, name), ((string Category, string Name) key) =>
            {
                // generates log name as combination of category and sanitized name
                var logName = $"{ChatLogNamePrefix}/{key.Category}/{PathUtils.SanitizeFileName(key.Name)}";
                return NLogManager.GetLogWriter(logName);
            });
            logger.Write(message);
        }
    }
}
