﻿using AsmodeeDigital.Common.Plugin.Manager.Event;
using AsmodeeDigital.Common.Plugin.Utils.Extensions;
using AsmodeeDigital.PlayReal.Plugin.Domain.GameConfiguration;
using AsmodeeDigital.PlayReal.Plugin.Logic;
using AsmodeeDigital.PlayReal.Plugin.Manager.Persistence;
using AsmodeeDigital.PlayReal.Plugin.Network;
using AsmodeeDigital.PlayReal.Samples.UI.LobbyPlayers;
using com.daysofwonder;
using com.daysofwonder.async;
using System;

namespace AsmodeeDigital.PlayReal.Samples.Logic
{
    /// <summary>
    /// Logic of the chat in lobby and in game
    /// </summary>
    public class ChatLogic : LogicBase, IDisposable
    {
        #region Events
        /// <summary>
        /// Chat message reception event
        /// </summary>
        public event Action<ChatEntry> ClientChatEvent;
        #endregion

        private DateTime _dateTimeLastChatEntry = DateTime.MinValue;

        public ChatLogic(ServerConnection serverConnection, Persistence persistence) : base(serverConnection, persistence)
        {
        }

        /// <summary>
        /// Initialize the view - Create .Net events on the server
        /// </summary>
        public void Init()
        {
            ServerConnection.ClientChatHistoryEvent += ServerConnection_ClientChatHistoryEvent;
            ServerConnection.ClientChatEvent += ServerConnection_ClientChatEvent;
            ServerConnection.ClientChatBlockedEvent += ServerConnection_ClientChatBlockedEvent;

            if (Persistence.CurrentGameDetails != null)
                ServerConnection.GetChatHistoryRequest(Persistence.CurrentGameDetails.game_id);
            else
                ServerConnection.GetChatHistoryRequest();
        }

        #region private methods
        /// <summary>
        /// Send caht to the Scalable Server
        /// </summary>
        /// <param name="chat"></param>
        /// <param name="gameId"></param>
        private void SendChat(string chat, Int64? gameId)
        {
            ServerConnection.MultiCastChatRequest(chat, gameId);
        }

        /// <summary>
        /// Get chat entry from Chat history entry
        /// </summary>
        /// <param name="chatHistoryEntry"></param>
        private void GetChat(ChatHistoryEntry chatHistoryEntry)
        {
            ChatEntry chatEntry = new ChatEntry();
            chatEntry.PlayerName = chatHistoryEntry.from;
            chatEntry.Text = chatHistoryEntry.text;
            chatEntry.DateTime = DateTime.Now.UnixTimeStampToDateTime(chatHistoryEntry.timestamp);

            if (chatEntry.DateTime.Subtract(_dateTimeLastChatEntry).TotalDays >= 1)
                chatEntry.ShowDate = true;

            _dateTimeLastChatEntry = chatEntry.DateTime;

            //---> In lobby, the player_id is www id
            if (Persistence.GameType == GameType.None)
                chatEntry.IsLocalPlayer = Persistence.ConnectedPlayer.w_w_w_id == chatHistoryEntry.player_id;
            //---> In game, the player id is local player id
            else
            {
                Player player = Persistence.CurrentGameDetails.players.Find(p => p.id == chatHistoryEntry.player_id);

                chatEntry.IsLocalPlayer = Persistence.ConnectedPlayer.w_w_w_id == player.w_w_w_id;
            }

            if (ClientChatEvent != null)
                EventManager.Instance.QueueEvent(ClientChatEvent, chatEntry);
        }

        /// <summary>
        /// Get chat entry from client chat request
        /// </summary>
        /// <param name="clientChatRequest"></param>
        private void GetChat(ClientChatRequest clientChatRequest)
        {
            //---> Do not show in game message in the lobby and vice versa
            if (clientChatRequest.game_id == 0L && Persistence.GameType != GameType.None ||
                clientChatRequest.game_id != 0L && Persistence.GameType == GameType.None)
                return;

            ChatEntry chatEntry = new ChatEntry();
            chatEntry.PlayerName = clientChatRequest.sender.name;
            chatEntry.Text = clientChatRequest.text;
            chatEntry.DateTime = DateTime.Now;
            chatEntry.IsLocalPlayer = Persistence.ConnectedPlayer.w_w_w_id == clientChatRequest.sender.w_w_w_id;

            if (chatEntry.DateTime.Subtract(_dateTimeLastChatEntry).TotalDays >= 1)
                chatEntry.ShowDate = true;

            _dateTimeLastChatEntry = chatEntry.DateTime;

            if (ClientChatEvent != null)
                EventManager.Instance.QueueEvent(ClientChatEvent, chatEntry);
        }
        #endregion

        #region Public methods accessed by view
        /// <summary>
        /// Sends a chat to the server
        /// </summary>
        /// <param name="text"></param>
        public void SendChatToLobby(string chat)
        {
            SendChat(chat, null);
        }

        /// <summary>
        /// Sends a chat to the server
        /// </summary>
        /// <param name="text"></param>
        public void SendChatToCurrentGame(string chat)
        {
            SendChat(chat, Persistence.CurrentGameDetails.game_id);
        }
        #endregion

        #region Network events
        /// <summary>
        /// Event raised by the server to refresh chat history
        /// </summary>
        /// <param name="clientChatHistoryRequest"></param>
        private void ServerConnection_ClientChatHistoryEvent(ClientChatHistoryRequest clientChatHistoryRequest)
        {
            foreach (ChatHistoryEntry chatHistoryEntry in clientChatHistoryRequest.entry)
            {
                GetChat(chatHistoryEntry);
            }
        }

        /// <summary>
        /// Event raised by the server when a chat message arrive
        /// </summary>
        /// <param name="clientChatRequest"></param>
        private void ServerConnection_ClientChatEvent(ClientChatRequest clientChatRequest)
        {
            GetChat(clientChatRequest);
        }

        /// <summary>
        /// Event raised by the server when a message sent by the player is blocked (anti-profanity filter)
        /// </summary>
        /// <param name="clientChatBlockedRequest"></param>
        private void ServerConnection_ClientChatBlockedEvent(ClientChatBlockedRequest clientChatBlockedRequest)
        {
            if (clientChatBlockedRequest.sender.w_w_w_id == Persistence.ConnectedPlayer.w_w_w_id)
            {
                ChatEntry chatEntry = new ChatEntry();
                chatEntry.PlayerName = "Big brother";
                chatEntry.Text = "I'm sure you do not want to say this, however I decided to mute you for a while";
                chatEntry.DateTime = DateTime.Now;
                chatEntry.IsLocalPlayer = false;
                chatEntry.IsCensored = true;

                if (ClientChatEvent != null)
                    EventManager.Instance.QueueEvent(ClientChatEvent, chatEntry);
            }
        }
        #endregion

        /// <summary>
        /// Dispose events
        /// </summary>
        public void Dispose()
        {
            ServerConnection.ExitLobbyRequest();

            ServerConnection.ClientChatHistoryEvent -= ServerConnection_ClientChatHistoryEvent;
            ServerConnection.ClientChatEvent -= ServerConnection_ClientChatEvent;
            ServerConnection.ClientChatBlockedEvent -= ServerConnection_ClientChatBlockedEvent;
        }
    }
}
