namespace Stove.StoveSDK
{
    using System;
    using System.Collections.Generic;
    using MiniJSON;
    using UnityEngine;

    /**
     * Unique value to distinguish between accounts.
     * @since 2.0.0
     */
    public class User
    {
        /**
         * Unique value to distinguish between accounts.
         * @since 2.0.0
         */
        public string UserId { get; }

        /**
         * Unique value to distinguish between accounts.
         * @since 2.0.0
         */
        public long MemberNumber { get; set; }

        /**
         * Account information for other platforms associated with Stove Account.
         *
         * Key is [Provider.providerType].
         *
         * Value is the user ID of the provider.
         *
         * For guests this is an empty map.
         * @since 2.0.0
         */
        public List<ProviderUser> ProviderUsers { get; }

        /**
         * Game Profile.
         * @since 2.0.0
         */
        private GameProfile gameProfile;
        public GameProfile GameProfile
        {
            get
            {
                return gameProfile;
            }

            set
            {
                if(gameProfile != null)
                {
                    gameProfile.needToCallAuthInterface = false;
                }
                gameProfile = value;
                Debug.Log("User.SetGameProfile");
                if (gameProfile != null)
                {
                    gameProfile.needToCallAuthInterface = true;
                    AuthInterface.SetGameProfile(gameProfile.ToJSONString());
                }
                else
                {
                    AuthInterface.SetGameProfile("");
                }
            }
        }

        /**
         * Member country based on memberNumber.
         * ISO 3166-1 alpha-2 code. (two-letter country code)
         * @since 2.0.0
         */
        public string Nationality { get; }

        /**
         * Identity authentication.
         * @since 2.0.0
         */
        public bool VerifiedIdentity { get; }
        
        /**
         * Verified of age.
         * @since 2.6.0
         */
        public bool VerifiedAge { get; }
        
        /**
         * Verified of Device.
         * @since 2.7.1
         */
        public bool VerifiedDevice { get; }

        /**
         * Device Registration Policy
         * @since 2.8.1
         */
        bool DeviceRegistrationPolicy { get; }

        public User(string userId, List<ProviderUser> providerUsers, long memberNumber, string nationality, bool verifiedIdentity, bool verifiedAge, bool verifiedDevice, bool deviceRegistrationPolicy, GameProfile gameProfile = null)
        {
            UserId = userId;
            ProviderUsers = providerUsers;
            MemberNumber = memberNumber;
            GameProfile = gameProfile;
            Nationality = nationality;
            VerifiedIdentity = verifiedIdentity;
            VerifiedAge = verifiedAge;
            VerifiedDevice = verifiedDevice;
            DeviceRegistrationPolicy = deviceRegistrationPolicy;
        }

        /**
         * Dictionary deserialization.
         * @since 2.0.0
         */
        public User(Dictionary<string, object> dictionary)
        {
            if (dictionary.ContainsKey("userId"))
            {
                UserId = dictionary["userId"] as string;
            }
            else
            {
                UserId = ""; 
            }

            if (dictionary.ContainsKey("memberNumber"))
            {
                MemberNumber = Convert.ToInt64(dictionary["memberNumber"]);
            }
            else
            {
                MemberNumber = 0; 
            }

            List<ProviderUser> providerUsers = new List<ProviderUser>();

            List<object> providerUserList = dictionary["providerUsers"] as List<object>;
            foreach (object obj in providerUserList)
            {
                ProviderUser providerUser = new ProviderUser(obj as Dictionary<string, object>);
                providerUsers.Add(providerUser);
            }

            ProviderUsers = providerUsers;

            if (dictionary.ContainsKey("gameProfile"))
            {
                gameProfile = new GameProfile(dictionary["gameProfile"] as Dictionary<string, object>);
                gameProfile.needToCallAuthInterface = true;
            }

            if (dictionary.ContainsKey("nationality"))
            {
                Nationality = dictionary["nationality"] as string;
            }
            else
            {
                Nationality = ""; 
            }

            VerifiedIdentity = Convert.ToBoolean(dictionary["verifiedIdentity"]);
            
            VerifiedAge = Convert.ToBoolean(dictionary["verifiedAge"]);

            VerifiedDevice = Convert.ToBoolean(dictionary["verifiedDevice"]);

            DeviceRegistrationPolicy = Convert.ToBoolean(dictionary["deviceRegistrationPolicy"]);
        }

        /**
         * Dictionary serialization.
         * @since 2.0.0
         */
        public Dictionary<string, object> ToDictionary()
        {
            Dictionary<string, object> dictionary = new Dictionary<string, object>();
            dictionary.Add("userId", UserId);
            
            List<Dictionary<string, object>> providerUsers = new List<Dictionary<string, object>>();

            foreach (ProviderUser providerUser in ProviderUsers)
            {
                providerUsers.Add(providerUser.ToDictionary());
            }

            dictionary.Add("providerUsers", providerUsers);

            dictionary.Add("memberNumber", MemberNumber);

            if (GameProfile != null)
            {
                dictionary.Add("gameProfile", GameProfile.ToDictionary());
            }

            dictionary.Add("nationality", Nationality);
            dictionary.Add("verifiedIdentity", VerifiedIdentity);
            dictionary.Add("verifiedAge", VerifiedAge);
            dictionary.Add("verifiedDevice", VerifiedDevice);            
            dictionary.Add("deviceRegistrationPolicy", DeviceRegistrationPolicy);

            return dictionary;
        }

        /**
         * JSON serialization.
         * @since 2.0.0
         */
        public string ToJSONString()
        {
            Dictionary<string, object> dictionary = ToDictionary();

            return Json.Serialize(dictionary);
        }

        /**
         * Whether guest.
         * @return Whether guest.
         * @since 2.0.0
         */
        public Boolean IsGuest()
        {
            return ProviderUsers.Count <= 0?true:false;
        }

        /**
         * Connect provider to current account.
         *
         * Guest account only.
         * @param provider Provider to link.
         * @param action Link result.
         * @since 2.0.0
         */
        public void Link(Provider provider, Action<Result> action)
        {
            Debug.Log("User.Link Provider(" + provider + "), Action(" + action + ")");
            string identifier = StoveSDK.Instance.AddAction(payload =>
            {
                Result result = new Result(payload["result"] as Dictionary<string, object>);
                Debug.Log("User.Link Result(" + result + ")");
                action.Invoke(result);
            });

            if (provider.User == null)
            {
                var method = provider.GetType().GetMethod("ToJSONString");
                if (method == null)
                {
                    AuthInterface.Link(provider.ClassName, identifier);
                }
                else
                {
                    string jsonString = method.Invoke(provider, null) as string;
                    AuthInterface.LinkGeneral(provider.ClassName, jsonString, identifier);
                }
            }
            else
            {
                var method = provider.GetType().GetMethod("ToJSONString");
                if (method == null)
                {
                    AuthInterface.LinkGeneric(provider.ClassName, Json.Serialize(provider.User), identifier);
                }
                else
                {
                    string jsonString = method.Invoke(provider, null) as string;
                    AuthInterface.LinkGeneral(provider.ClassName, jsonString, identifier);
                }
            }
        }

        public override string ToString()
        {
            string providerUsers = "";
            if(ProviderUsers != null)
            {
                foreach (ProviderUser user in ProviderUsers)
                {
                    providerUsers += user;
                }
            }
            return "User(UserId='" + UserId
                + "', MemberNumber='" + MemberNumber
                + "', ProviderUsers=" + providerUsers
                + ", Nationality='" + Nationality
                + "', VerifiedIdentity='" + VerifiedIdentity
                + "', VerifiedAge=" + VerifiedAge
		        + "', VerifiedDevice =" + VerifiedDevice
                + "', DeviceRegistrationPolicy=" + DeviceRegistrationPolicy
                + "', GameProfile=" + GameProfile
                + ")";
        }
    }

}
