﻿using AsmodeeDigital.PlayReal.Plugin.Logic;
using AsmodeeDigital.Common.Plugin.Manager.Event;
using AsmodeeDigital.PlayReal.Plugin.Manager.Persistence;
using AsmodeeDigital.Common.Plugin.Manager.Scene;
using AsmodeeDigital.PlayReal.Plugin.Network;
using com.daysofwonder.async;
using System;
using System.Text;
using UnityEngine;

namespace AsmodeeDigital.PlayReal.Samples.Logic
{
    /// <summary>
    /// Logic of the main menu view
    /// </summary>
    [Serializable]
    public class MainMenuLogic : LogicBase, IDisposable
    {
        #region Events
        /// <summary>
        /// Event fired when the user is connected to the server
        /// </summary>
        public event Action ConnectedToServerEvent;

        /// <summary>
        /// Event fired when the user is disconnected from the server
        /// </summary>
        public event Action DisconnectedFromServerEvent;

        /// <summary>
        /// Event fired when the user is authenticated
        /// </summary>
        public event Action<AsyncConnectedRequest> AuthenticatedEvent;
        #endregion

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

        /// <summary>
        /// Initialize the view - Create .Net events on the server
        /// </summary>
        public void Init()
        {
            ServerConnection.ConnectedToServerEvent += ServerConnection_ConnectedToServerEvent;
            ServerConnection.DisconnectedFromServerEvent += ServerConnection_DisconnectedFromServerEvent;
            ServerConnection.AsyncConnectedEvent += ServerConnection_AsyncConnectedEvent;
            ServerConnection.AsyncConnectionErrorEvent += ServerConnection_AsyncConnectionErrorEvent;

#if UNITY_IOS
            RegisterForNotificationPush();
#endif
        }

        #region Private methods
#if UNITY_IOS
        private void RegisterForNotificationPush()
        {
            UnityEngine.iOS.NotificationServices.RegisterForNotifications(UnityEngine.iOS.NotificationType.Alert |
                                                                          UnityEngine.iOS.NotificationType.Badge |
                                                                          UnityEngine.iOS.NotificationType.Sound);
        }
#endif
        #endregion

        #region Public methods accessed by view
        /// <summary>
        /// Connect the user to the server
        /// </summary>
        public void Connect()
        {
            ServerConnection.Connect();
        }

        /// <summary>
        /// Disconnect the user from the server
        /// </summary>
        public void Disconnect()
        {
            if (ServerConnection.ConnectionState >= ConnectionState.Connected)
                ServerConnection.Disconnect();
            else
                ServerConnection_DisconnectedFromServerEvent();
        }

        /// <summary>
        /// Authenticate the user on the server
        /// </summary>
        /// <param name="login">Login of the user</param>
        /// <param name="password">Password of the user</param>
        public void AuthenticateUser(string login, string password)
        {
#if UNITY_IOS
            ServerConnection.AuthenticateUser(login, password, Persistence.Session, com.daysofwonder.game.push.Devices.Type.IOS, UnityEngine.iOS.NotificationServices.deviceToken);
#elif UNITY_ANDROID

            //Note : SystemInfo.deviceUniqueIdentifier add READ_PHONE_STATE permission to the manifest
            byte[] deviceId = Encoding.ASCII.GetBytes(SystemInfo.deviceUniqueIdentifier);
            ServerConnection.AuthenticateUser(login, password, Persistence.Session, com.daysofwonder.game.push.Devices.Type.GCM, deviceId);
#else
            ServerConnection.AuthenticateUser(login, password, Persistence.Session, com.daysofwonder.game.push.Devices.Type.STEAM, null);
#endif
        }

        /// <summary>
        /// Show create game view
        /// </summary>
        public void ShowLobbyView()
        {
            SceneManager.LoadScene("2_Lobby");
        }
        #endregion

        #region Network events
        /// <summary>
        /// Event called when the user is connected to the server
        /// </summary>
        private void ServerConnection_ConnectedToServerEvent()
        {
            if (ConnectedToServerEvent != null)
                EventManager.Instance.QueueEvent(ConnectedToServerEvent);
        }

        /// <summary>
        /// Event called when the user is disconnected from the server
        /// </summary>
        private void ServerConnection_DisconnectedFromServerEvent()
        {
            if (DisconnectedFromServerEvent != null)
                EventManager.Instance.QueueEvent(DisconnectedFromServerEvent);
        }

        /// <summary>
        /// Event called when the user is authenticated on the server
        /// </summary>
        /// <param name="asyncConnectedRequest"></param>
        private void ServerConnection_AsyncConnectedEvent(AsyncConnectedRequest asyncConnectedRequest)
        {
            Persistence.Session = asyncConnectedRequest.session;
            Persistence.ConnectedPlayer = asyncConnectedRequest.player;

            if (AuthenticatedEvent != null)
                EventManager.Instance.QueueEvent(AuthenticatedEvent, asyncConnectedRequest);
        }

        /// <summary>
        /// Event called when there is an error with the user authentication
        /// </summary>
        /// <param name="asyncConnectionErrorRequest"></param>
        private void ServerConnection_AsyncConnectionErrorEvent(AsyncConnectionErrorRequest asyncConnectionErrorRequest)
        {
            Debug.Log(String.Format("User connection error : {0}", asyncConnectionErrorRequest.code));
        }
        #endregion

        /// <summary>
        /// Dispose events
        /// </summary>
        public void Dispose()
        {
            ServerConnection.ConnectedToServerEvent -= ServerConnection_ConnectedToServerEvent;
            ServerConnection.DisconnectedFromServerEvent -= ServerConnection_DisconnectedFromServerEvent;
            ServerConnection.AsyncConnectedEvent -= ServerConnection_AsyncConnectedEvent;
            ServerConnection.AsyncConnectionErrorEvent -= ServerConnection_AsyncConnectionErrorEvent;
        }
    }
}
