﻿using AsmodeeDigital.PlayReal.Plugin.Logic;
using AsmodeeDigital.Common.Plugin.Manager.Event;
using AsmodeeDigital.PlayReal.Plugin.Manager.Persistence;
using AsmodeeDigital.PlayReal.Plugin.Network;
using com.daysofwonder;
using com.daysofwonder.async;
using System;
using System.Collections.Generic;

namespace AsmodeeDigital.PlayReal.Samples.Logic
{
    /// <summary>
    /// Logic of the lobby players view
    /// </summary>
    [Serializable]
    public class LobbyPlayersLogic : LogicBase, IDisposable
    {
        #region Events
        /// <summary>
        /// Refresh current player list event
        /// </summary>
        public event Action RefreshLobbyPlayerListEvent;

        /// <summary>
        /// Player info event
        /// </summary>
        public event Action<LobbyPlayerInfoRequest> LobbyPlayerInfoEvent;
        #endregion

        #region Cache
        /// <summary>
        /// Buddy list
        /// </summary>
        private AsyncBuddyListContentRequest _asyncBuddyListContentRequest;

        /// <summary>
        /// Ignore list
        /// </summary>
        private AsyncIgnoreListContentRequest _asyncIgnoreListContentRequest;

        /// <summary>
        /// Online players list
        /// </summary>
        private List<SmallPlayer> _onlinePlayers;
        #endregion

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

        /// <summary>
        /// Initialize the view - Create .Net events on the server
        /// </summary>
        public void Init()
        {
            ServerConnection.LobbyPlayerListEvent += ServerConnection_LobbyPlayerListEvent;
            ServerConnection.AsyncBuddyListContentEvent += ServerConnection_AsyncBuddyListContentEvent;
            ServerConnection.AsyncIgnoreListContentEvent += ServerConnection_AsyncIgnoreListContentEvent;
            ServerConnection.LobbyPlayerInfoEvent += ServerConnection_LobbyPlayerInfoEvent;

            ServerConnection.EnterLobbyRequest();
            
            ServerConnection.AsyncBuddyListRequest();
            ServerConnection.AsyncIgnoreListRequest();
        }

        #region Public methods accessed by view
        /// <summary>
        /// Get a IPlayer by his DoWId
        /// </summary>
        /// <param name="DoWId"></param>
        /// <returns></returns>
        public IPlayer GetBuddy(int DoWId)
        {
            IPlayer player = null;

            player = _onlinePlayers.Find(p => p.w_w_w_id == DoWId);

            if (player == null)
                player = _asyncBuddyListContentRequest.buddies.player.Find(p => p.w_w_w_id == DoWId);

            if (player == null)
                player = _asyncIgnoreListContentRequest.ignores.player.Find(p => p.w_w_w_id == DoWId);

            return player;
        }

        /// <summary>
        /// Get online players
        /// </summary>
        /// <returns></returns>
        public List<IPlayer> GetOnlinePlayers()
        {
            if (_onlinePlayers != null)
                return _onlinePlayers.ConvertAll<IPlayer>(p => (IPlayer)p);
            else
                return null;
        }

        /// <summary>
        /// Get ignored players list
        /// </summary>
        /// <returns></returns>
        public List<IPlayer> GetIgnoredPlayers()
        {
            if (_asyncIgnoreListContentRequest != null && _asyncIgnoreListContentRequest.ignores != null)
                return _asyncIgnoreListContentRequest.ignores.player.ConvertAll<IPlayer>(p => (IPlayer)p);
            else
                return null;
        }

        /// <summary>
        /// Get buddy list
        /// </summary>
        /// <returns></returns>
        public List<IPlayer> GetFriendsPlayers()
        {
            if (_asyncBuddyListContentRequest != null && _asyncBuddyListContentRequest.buddies != null)
                return _asyncBuddyListContentRequest.buddies.player.ConvertAll<IPlayer>(p => (IPlayer)p);
            else
                return null;
        }

        /// <summary>
        /// Get status of a player by his DoWId
        /// </summary>
        /// <param name="DoWId"></param>
        /// <returns></returns>
        public BuddyStatus GetBuddyStatus(int DoWId)
        {
            if (_asyncBuddyListContentRequest.buddies.player.Exists(p => p.w_w_w_id == DoWId))
                return BuddyStatus.Friend;
            else if (_asyncIgnoreListContentRequest.ignores.player.Exists(p => p.w_w_w_id == DoWId))
                return BuddyStatus.Ignored;
            else
                return BuddyStatus.None;
        }

        /// <summary>
        /// Add a player to the buddy list
        /// </summary>
        /// <param name="DoWId"></param>
        public void AddToBuddyList(int DoWId)
        {
            ServerConnection.AddBuddy(DoWId);
            ServerConnection.AsyncBuddyListRequest();
        }

        /// <summary>
        /// Addd a player to the ignore list
        /// </summary>
        /// <param name="DoWId"></param>
        public void AddToIgnoreList(int DoWId)
        {
            ServerConnection.AddToIgnore(DoWId);
            ServerConnection.AsyncIgnoreListRequest();
        }

        /// <summary>
        /// Remove a player from the buddy list
        /// </summary>
        /// <param name="DoWId"></param>
        public void RemoveFromBuddyList(int DoWId)
        {
            ServerConnection.RemoveBuddy(DoWId);
            ServerConnection.AsyncBuddyListRequest();
        }

        /// <summary>
        /// Remove a player from the ignore list
        /// </summary>
        /// <param name="DoWId"></param>
        public void RemoveFromIgnoreList(int DoWId)
        {
            ServerConnection.RemoveFromIgnore(DoWId);
            ServerConnection.AsyncIgnoreListRequest();
        }

        /// <summary>
        /// Ask player infos. LobbyPlayerInfoEvent will raise when the infos arrive
        /// </summary>
        /// <param name="DoWId"></param>
        public void AskPlayerInfos(int DoWId)
        {
            ServerConnection.AskPlayerInfoRequest(DoWId);
        }
        #endregion

        #region Network events
        /// <summary>
        /// Event fired by the server regularly to refresh the lobby player list
        /// </summary>
        /// <param name="players"></param>
        private void ServerConnection_LobbyPlayerListEvent(List<SmallPlayer> players)
        {
            _onlinePlayers = players;

            if (RefreshLobbyPlayerListEvent != null)
                EventManager.Instance.QueueEvent(RefreshLobbyPlayerListEvent);
        }

        /// <summary>
        /// Event fired by the server to refresh the buddy list
        /// </summary>
        /// <param name="asyncBuddyListContentRequest"></param>
        private void ServerConnection_AsyncBuddyListContentEvent(AsyncBuddyListContentRequest asyncBuddyListContentRequest)
        {
            _asyncBuddyListContentRequest = asyncBuddyListContentRequest;

            if (RefreshLobbyPlayerListEvent != null)
                EventManager.Instance.QueueEvent(RefreshLobbyPlayerListEvent);
        }

        /// <summary>
        /// Event fired by the server to refresh the ignore list
        /// </summary>
        /// <param name="asyncIgnoreListContentRequest"></param>
        private void ServerConnection_AsyncIgnoreListContentEvent(AsyncIgnoreListContentRequest asyncIgnoreListContentRequest)
        {
            _asyncIgnoreListContentRequest = asyncIgnoreListContentRequest;

            if (RefreshLobbyPlayerListEvent != null)
                EventManager.Instance.QueueEvent(RefreshLobbyPlayerListEvent);
        }

        /// <summary>
        /// Event fired by the server after AskPlayerInfoRequest
        /// </summary>
        /// <param name="lobbyPlayerInfoRequest"></param>
        private void ServerConnection_LobbyPlayerInfoEvent(LobbyPlayerInfoRequest lobbyPlayerInfoRequest)
        {
            if (LobbyPlayerInfoEvent != null)
                EventManager.Instance.QueueEvent(LobbyPlayerInfoEvent, lobbyPlayerInfoRequest);
        }
        #endregion

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

            ServerConnection.LobbyPlayerListEvent -= ServerConnection_LobbyPlayerListEvent;
            ServerConnection.AsyncBuddyListContentEvent -= ServerConnection_AsyncBuddyListContentEvent;
            ServerConnection.AsyncIgnoreListContentEvent -= ServerConnection_AsyncIgnoreListContentEvent;
            ServerConnection.LobbyPlayerInfoEvent -= ServerConnection_LobbyPlayerInfoEvent;
        }
    }

    public enum BuddyStatus
    {
        None,
        Friend,
        Ignored
    }
}
