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

    /**
     * Auth provided by the Stove.
     * @since 2.0.0
     */
    public class Auth
    {
        /**
         * Auth's domain
         * @since 2.0.0
         */
        public const string Domain = "com.stove.auth";

        /**
         * Setup error. check remote constants of the stove platform.
         * @since 2.0.0
         */
        public const int AuthConfigurationError = 30001;

        /**
         * When authentication is not completed.
         * @since 2.0.0
         */
        public const int UnauthorizedError = 30002;

        /**
         * App maintenance.
         * @since 2.0.0
         */ 
        public const int MaintenanceError = 30003;

        /**
         * App update required.
         * @since 2.0.0
         */
        public const int AppUpdateError = 30004;

        /**
         * Load the remote constants of the stove platform. Information obtained at this time is to load HTTP Request timeout and platform setting information.
         *
         * Initialization can only be done once during the application life cycle.
         *
         * Calling it again after initialization does not reload the remote constants separately.
         *
         * @param action Initialize Result.
         * @see Result
         * @since 2.0.0
         */
        public static void Initialize(Action<Result> action)
        {
            Debug.Log("Auth.Initialize Action(" + action + ")");
            string identifier = StoveSDK.Instance.AddAction(payload =>
            {
                Result result = new Result(payload["result"] as Dictionary<string, object>);
                Debug.Log("Auth.Initialize Result(" + result + ")");
                action.Invoke(result);
            });
            AuthInterface.Initialize(identifier);
        }

        /**
         * Loads the stove platform remote constant for the input version. Information obtained at this time is to load HTTP Request timeout and platform setting information.
         *
         * Initialization can only be done once during the application life cycle.
         *
         * Calling it again after initialization does not reload the remote constants separately.
         * 
         * @param version Config server version
         * @param action Initialize Result.
         * @see Result
         * @since 2.4.0
         */
        public static void Initialize(String version, Action<Result> action)
        {
            Debug.Log("Auth.Initialize Version(" + version + "), Action(" + action + ")");
            string identifier = StoveSDK.Instance.AddAction(payload =>
            {
                Result result = new Result(payload["result"] as Dictionary<string, object>);
                Debug.Log("Auth.Initialize Result(" + result + ")");
                action.Invoke(result);
            });
            AuthInterface.Initialize(identifier, version);
        }


        /**
         * Register with the provider information.
         *
         * In order to proceed, you will first need to view the terms and conditions and accept the terms.
         *
         * If you have already registered, you will fail.
         *
         * @param provider Provider to login.
         * @param list List of Terms.
         * @param action Login Result.
         * @see Provider
         * @see TermsOfServiceData
         * @see Result
         * @see AccessToken
         * @since 2.0.0
         */
        public static void Register(Provider provider, List<TermsOfServiceData> list, Action<Result, AccessToken> action)
        {
            Debug.Log("Auth.Register Provider(" + provider + "), List(" + list + "), Action(" + action + ")");
            string identifier = StoveSDK.Instance.AddAction(payload =>
            {
                Result result = new Result(payload["result"] as Dictionary<string, object>);
                AccessToken accessToken = GetAccessTokenFromDictionary(payload);
                Debug.Log("Auth.Register Result(" + result + "), AccessToken(" + accessToken + ")");
                action.Invoke(result, accessToken);
            });

            if (provider.User == null)
            {
                AuthInterface.Register(provider.ClassName, GetTermsOfServiceDataListString(list), identifier);
            }
            else
            {

                AuthInterface.RegisterGeneric(provider.ClassName, Json.Serialize(provider.User), GetTermsOfServiceDataListString(list), identifier);
            }
        }

        private static string GetTermsOfServiceDataListString(List<TermsOfServiceData> termsOfServiceDataList)
        {
            List<Dictionary<string, object>> list = new List<Dictionary<string, object>>();
            foreach (TermsOfServiceData termsOfServiceData in termsOfServiceDataList)
            {
                list.Add(termsOfServiceData.ToDictionary());
            }
            return Json.Serialize(list);
        }

        internal static AccessToken GetAccessTokenFromDictionary(Dictionary<string, object> payload)
        {
            AccessToken accessToken = null;
            if (payload.ContainsKey("accessToken"))
            {
                accessToken = new AccessToken(payload["accessToken"] as Dictionary<string, object>);
            }
            return accessToken;
        }

        /**
         * Log in with the provider information.
         *
         * If you haven't signed up, your login will fail.
         *
         * For guests, use sign up instead of login.
         * @param provider Provider to login.
         * @param action Login Result.
         * @see Provider
         * @see Result
         * @see AccessToken
         * @since 2.0.0
         */
        public static void Login(Provider provider, Action<Result, AccessToken> action)
        {
            Debug.Log("Auth.Login Provider(" + provider + "), Action(" + action + ")");
            string identifier = StoveSDK.Instance.AddAction(payload =>
            {
                Result result = new Result(payload["result"] as Dictionary<string, object>);
                AccessToken accessToken = GetAccessTokenFromDictionary(payload);
                Debug.Log("Auth.Login Result(" + result + "), AccessToken(" + accessToken + ")");
                action.Invoke(result, accessToken);
            });

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

        /**
         * Log out of current account.
         *
         * [AccessToken] changes to null after logout.
         *
         * After you leave, you must be able to log in again.
         *
         * Guest has no way to find account when logging out.
         * @since 2.0.0
         */
        public static void Logout()
        {
            Debug.Log("Auth.Logout");
            AuthInterface.Logout();
        }

        /**
         * Fetch currently logged in account information.
         * @return Currently logged in account information.
         * @since 2.0.0
         */
        public static AccessToken AccessToken
        {
            get
            {
                AccessToken accessToken = null;
                string accessTokenString = AuthInterface.GetAccessToken();
                if (accessTokenString != null)
                {
                    accessToken = new AccessToken(Json.Deserialize(accessTokenString) as Dictionary<string, object>);
                }
                Debug.Log("Auth.GetAccessToken(" + accessToken + ")");
                return accessToken;
            }
            set
            {
                Debug.Log("Auth.SetAccessToken(" + value + ")");
                Dictionary<string, object> dictionary = value.ToDictionary();
                string accessTokenString = Json.Serialize(dictionary);

                Debug.Log("Auth.SetAccessToken2(" + accessTokenString + ")");
                AuthInterface.SetAccessToken(accessTokenString);
            }
        }

        /**
        * Auth Version
        * @since 2.3.0
        */
        public static string GetVersion()
        {
            Debug.Log("GetVersion");

            string version = AuthInterface.GetVersion();

            Debug.Log("GetVersion return : " + version);

            return version;
        }

        public static bool IsMain(String providerCode)
        {
            Debug.Log("IsMain");
            bool isMain = AuthInterface.IsMain(providerCode);
            Debug.Log("IsMain return : " + isMain);
            return isMain;
        }

        /// <summary>
        /// 플레이타임 메시지 리스너 설정.
        /// Auth.Initialize 성공 후 호출.
        /// 로그인 상태에서 주기적으로 플레이타임 안내 메시지를 수신.
        /// </summary>
        public static void SetPlaytimeListener(Action<Dictionary<string, string>> listener)
        {
            Debug.Log("Auth.SetPlaytimeListener");
            string identifier = StoveSDK.Instance.AddAction(payload =>
            {
                Debug.Log("Auth.SetPlaytimeListener playtimeInfo : " + Json.Serialize(payload));

                Dictionary<string, string> playtimeInfo = new Dictionary<string, string>();
                foreach (var kvp in payload)
                {
                    playtimeInfo[kvp.Key] = kvp.Value != null ? kvp.Value.ToString() : "";
                }
                listener.Invoke(playtimeInfo);
            });
            AuthInterface.SetPlaytimeListener(identifier);
        }
    }
}

