using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using _Combo;
using _Combo.Events;
using _Core;
using _Core.Storage;

namespace Seayoo.ComboSDK.Windows.TapTap
{
    public class TapTapManager : Singleton<TapTapManager>
    {
        private TapTapManager() { }
        private static TapTapManager _instance;
        private const string autoLoginKey = "combosdk_taptap_auto_login";
        private TapTapLoginResult loginResult;

        public static TapTapManager GetInstance()
        {

            if (_instance == null)
            {
                if (_instance == null)
                {
                    _instance = new TapTapManager();
                }
            }
            return _instance;
        }

        public async Task Init()
        {
            if (Combo.Instance.GetDistro() == GlobalParameters.Instance.TaptapPCDistro)
            {
                TapTapInit.Init(Config.clientId, Config.clientToken, true, true, Config.clientPublicKey);
                UIController.Instance.ShowLoading();
                await TapTapInit.IsLaunchedFromTapTapPC((result) =>
                {
                    UIController.Instance.HideLoading();
                    if (result)
                    {
                        RegisterCallback();
                        SetupSuccessEvent.Invoke(new SetupSuccessEvent()
                        {
                            idp = "taptap"
                        });
                    }
                    else
                    {
                        var setupError = new InitializedError(InitializedErrorType.INIT_FAILED);
                        SetupFailedEvent.Invoke(new SetupFailedEvent { error = new InternalError(I18n.T("taptap_pc_startup_verify_failed"), setupError) });
                    }
                }, (error) =>
                {
                    UIController.Instance.HideLoading();
                    var setupError = new InitializedError(InitializedErrorType.INIT_FAILED, cause: error);
                    SetupFailedEvent.Invoke(new SetupFailedEvent { error = new InternalError(I18n.T("taptap_pc_startup_verify_failed"), setupError) });
                });
            }
            else
            {
                TapTapInit.Init(Config.clientId, Config.clientToken, true, true);
                RegisterCallback();
                SetupSuccessEvent.Invoke(new SetupSuccessEvent()
                {
                    idp = "taptap"
                });
            }
        }

        private void RegisterCallback()
        {
            Action<int, string> callback = (code, extra) =>
            {
                switch (code)
                {
                    case 500:
                        if (string.IsNullOrEmpty(loginResult.openId))
                        {
                            var error = new LoginError("taptap", LoginErrorType.ACCOUNT_INVALID, thirdPartyMessage: "profile.openid is not available");
                            LoginFailedEvent.Invoke(new LoginFailedEvent { error = new InternalError(I18n.T("credential_expired_error"), error) });
                            CloseLoginViewEvent.Invoke();
                            break;
                        }
                        var credential = new TaptapCredential()
                        {
                            kid = loginResult.accessToken.kid,
                            macKey = loginResult.accessToken.macKey,
                            ageRange = TapTapCompliance.GetAgeRange(),
                            name = loginResult.name
                        };
                        if (GlobalParameters.Instance.TaptapMustLinkSeayooAccount)
                        {
                            CheckLinkIdentityEvent.Invoke(new CheckLinkIdentityEvent
                            {
                                externalId = loginResult.openId,
                                credential = credential
                            });
                        }
                        else
                        {
                            LoginSuccessEvent.Invoke(new LoginSuccessEvent
                            {
                                credential = credential
                            });
                            CloseLoginViewEvent.Invoke();
                        }
                        break;
                    case 1030:
                    case 1050:
                        break;
                    case 1001:
                    case 1000:
                        LoginSwitchAccountEvent.Invoke(new LoginSwitchAccountEvent());
                        break;
                    case 9002:
                        var loginError = new LoginError("taptap", LoginErrorType.REAL_NAME_NOT_SUPPORT, 9002, I18n.T("real_name_cancelled_error"));
                        LoginFailedEvent.Invoke(new LoginFailedEvent { error = new InternalError(I18n.T("real_name_required_error"), loginError) });
                        CloseLoginViewEvent.Invoke();
                        break;
                    case 1100:
                        UIController.Instance.ShowAlertView(
                            I18n.T("common_dialog_title"),
                            I18n.T("fangchenmi_taptap_age_dialog_text"),
                            UnityEngine.TextAnchor.UpperLeft,
                            I18n.T("acknowledge_button"),
                            () =>
                            {
                                Logout();
                            }
                        );
                        break;
                    case 1200:
                        var err = new LoginError("taptap", LoginErrorType.UNKNOWN_ERROR, 1200, cause: new NetworkError());
                        LoginFailedEvent.Invoke(new LoginFailedEvent { error = new InternalError(I18n.T("network_error"), err) });
                        CloseLoginViewEvent.Invoke();
                        break;
                    default:
                        LoginFailedEvent.Invoke(new LoginFailedEvent
                        {
                            error = new InternalError(extra)
                        });
                        CloseLoginViewEvent.Invoke();
                        break;
                }
            };
            TapTapCompliance.RegisterComplianceCallback(callback);
        }

        public async void Login()
        {
            List<string> scopes = new List<string>
            {
                "public_profile"
            };
            UIController.Instance.ShowLoading();
            await TapTapLogin.LoginWithScopes(scopes.ToArray(), result =>
            {
                UIController.Instance.HideLoading();
                loginResult = result;
                TapTapCompliance.Startup(result.unionId);
            }, (err) =>
            {
                UIController.Instance.HideLoading();
                var userCancelled = ErrorExtensions.Convert<UserCancelled>(err);
                if (userCancelled != null)
                {
                    LoginCancelEvent.Invoke(new LoginCancelEvent { });
                    CloseLoginViewEvent.Invoke();
                }
                else
                {
                    LoginFailedEvent.Invoke(new LoginFailedEvent
                    {
                        error = err
                    });
                    CloseLoginViewEvent.Invoke();
                }
            });
        }

        public void Logout()
        {
            TapTapLogin.Logout();
            TapTapCompliance.Exit();
        }

        public async void AutoLogin(Action<bool> action)
        {
            await TapTapLogin.GetCurrentTapAccount(result =>
            {
                if (result == null)
                {
                    SetAutoLoginEnabled(false);
                    action.Invoke(false);
                    return;
                }
                loginResult = result;
                TapTapCompliance.Startup(result.unionId);
            }, (err) =>
            {
                LoginFailedEvent.Invoke(new LoginFailedEvent
                {
                    error = err
                });
                CloseLoginViewEvent.Invoke();
            });
        }

        public void SetAutoLoginEnabled(bool enabled)
        {
            UserPrefs.SetBool(autoLoginKey, enabled);
        }
        public bool GetAutoLoginEnabled()
        {
            return UserPrefs.GetBool(autoLoginKey);
        }
    }
}