using _Combo;
using _Core;
using Seayoo.ComboSDK.Windows.Account.Model.Net;
using System;
using System.Collections.Generic;
using UnityEngine;

namespace Seayoo.ComboSDK.Windows.Account.Net.v1
{
    internal static class AccountClient
    {
        private static string endpoint;
        private static string unitySdkVersion = "";
        private static string unityVersion = "";

        public static void Setup(string endpoint, string unitySdkVersion, string unityVersion)
        {
            AccountClient.endpoint = endpoint;
            AccountClient.unitySdkVersion = unitySdkVersion;
            AccountClient.unityVersion = unityVersion;
        }

        public static void GetLoginOptions(string account, Action<AccountResponse<GetLoginOptionsResponse>> onReceive, Action<InternalError> onError)
        {
            HttpRequest.Post(new HttpRequestOptions
            {
                url = RequestUrl("/v1/get-login-options"),
                body = new GetLoginOptionsRequest
                {
                    account = account,
                },
                headers = Headers()
            }, resp =>
            {
                if (resp.IsSuccess)
                    Log.D(resp.ToString());
                else
                    Log.D(resp.ToString());

                var accountResp = AccountResponse<GetLoginOptionsResponse>.CreateResponse(resp, RequestUrl("/v1/get-login-options"));

                if (accountResp.IsSuccess)
                {
                    onReceive.Invoke(accountResp);
                }
                else
                {
                    HandleError("GetLoginOptions", accountResp.Error, false);
                    onError(accountResp.Error);
                }
            });
        }

        public static void CreateCaptcha(string account, string action, Action<AccountResponse<CreateCaptchaResponse>> onReceive, Action onError)
        {
            HttpRequest.Post(new HttpRequestOptions
            {
                url = RequestUrl("/v1/create-captcha"),
                body = new CreateCaptchaRequest
                {
                    account = account,
                    action = action,
                },
                headers = Headers()
            }, resp =>
            {
                if (resp.IsSuccess)
                    Log.D(resp.ToString());
                else
                    Log.D(resp.ToString());

                var accountResp = AccountResponse<CreateCaptchaResponse>.CreateResponse(resp, RequestUrl("/v1/create-captcha"));

                if (accountResp.IsSuccess)
                {
                    onReceive.Invoke(accountResp);
                }
                else
                {
                    HandleError("CreateCaptcha", accountResp.Error);
                    onError();
                }
            });
        }

        public static void CreateLoginOTP(string mobile, string captchaId, Action<AccountResponse<CreateLoginOTPResponse>> onReceive, Action onError, string captchaResult = null)
        {
            var profile = GlobalParameters.Instance.SeayooAccountOtpProfile;
            
            HttpRequest.Post(new HttpRequestOptions
            {
                url = RequestUrl("/v1/create-login-otp"),
                body = new CreateLoginOTPRequest
                {
                    mobile = mobile,
                    profile = profile,
                    captchaId = captchaId,
                    captchaResult = captchaResult
                },
                headers = Headers()
            }, resp =>
            {
                if (resp.IsSuccess) Log.D(resp.ToString());
                else Log.D(resp.ToString());

                var accountResp = AccountResponse<CreateLoginOTPResponse>.CreateResponse(resp, RequestUrl("/v1/create-login-otp"));

                if (accountResp.IsSuccess) {
                    onReceive.Invoke(accountResp);
                } else {
                    HandleError("CreateLoginOTP", accountResp.Error);
                    onError();
                }
            });
        }

        public static void LoginWithOTP(LoginWithOTPRequest request, Action<AccountResponse<LoginWithOTPResponse>> onReceive, Action onError, Credential credential = null)
        {
            HttpRequest.Post(new HttpRequestOptions
            {
                url = RequestUrl("/v1/login-with-otp"),
                body = request,
                headers = Headers(),
            }, resp =>
            {
                if (resp.IsSuccess) Log.D(resp.ToString());
                else Log.D(resp.ToString());

                var accountResp = AccountResponse<LoginWithOTPResponse>.CreateResponse(resp, RequestUrl("/v1/login-with-otp"));

                if (accountResp.IsSuccess) {
                    onReceive(accountResp);
                } else {
                    HandleError("LoginWithOTP", accountResp.Error);
                    ErrorTrackingManager.Instance.CaptureException(accountResp.Error);
                    onError();
                }
            });
        }

        public static void VerifyLoginToken(VerifyLoginTokenRequest request, Action<AccountResponse<VerifyLoginTokenResponse>> onReceive, Action<ErrorResponse, string> onError)
        {
            HttpRequest.Post(
                new HttpRequestOptions
                {
                    url = RequestUrl("/v1/verify-login-token"),
                    body = request,
                    headers = Headers(),
                },
            resp =>
            {
                if (resp.IsSuccess) Log.D(resp.ToString());
                else Log.D(resp.ToString());

                var accountResp = AccountResponse<VerifyLoginTokenResponse>.CreateResponse(resp, RequestUrl("/v1/verify-login-token"));
                if (accountResp.IsSuccess) {
                    onReceive(accountResp);
                } else {
                    HandleError("verify-login-token", accountResp.Error);
                    ErrorTrackingManager.Instance.CaptureException(accountResp.Error);
                    onError(resp.Body.ToJson<ErrorResponse>(), request.userId);
                }
            });
        }

        public static void AuthRealName(AuthRealNameRequest request, Action<AccountResponse<AuthRealNameResponse>> onReceive, Action onError)
        {
            HttpRequest.Post(new HttpRequestOptions
            {
                url = RequestUrl("/v1/auth-real-name"),
                body = request,
                headers = Headers(),
            }, resp =>
            {
                if (resp.IsSuccess) Log.D(resp.ToString());
                else Log.D(resp.ToString());

                var accountResp = AccountResponse<AuthRealNameResponse>.CreateResponse(resp, RequestUrl("/v1/auth-real-name"));
                if (accountResp.IsSuccess) {
                    onReceive(accountResp);
                } else {
                    HandleError("auth-real-name", accountResp.Error);
                    ErrorTrackingManager.Instance.CaptureException(accountResp.Error);
                    onError();
                }
            });
        }

        public static void LoginWithPassword(LoginWithPasswordRequest request, Action<AccountResponse<LoginWithPasswordResponse>> onReceive, Action onError)
        {
            HttpRequest.Post(new HttpRequestOptions
            {
                url = RequestUrl("/v1/login-with-password"),
                body = request,
                headers = Headers(),
            }, resp =>
            {
                if (resp.IsSuccess) Log.D(resp.ToString());
                else Log.D(resp.ToString());

                var accountResp = AccountResponse<LoginWithPasswordResponse>.CreateResponse(resp, RequestUrl("/v1/login-with-password"));
                if(accountResp.IsSuccess) {
                    onReceive(accountResp);
                }
                else {
                    HandleError("login-with-password", accountResp.Error);
                    ErrorTrackingManager.Instance.CaptureException(accountResp.Error);
                    onError();
                }
            });
        }

        public static void CreateDeviceGrantOTP(CreateDeviceGrantOTPRequest request, Action<AccountResponse<CreateDeviceGrantOTPResponse>> onReceive, Action<ErrorResponse> onError)
        {
            HttpRequest.Post(new HttpRequestOptions
            {
                url = RequestUrl("/v1/create-device-grant-otp"),
                body = request,
                headers = Headers(),
            }, resp =>
            {
                if (resp.IsSuccess) Log.D(resp.ToString());
                else Log.D(resp.ToString());

                var accountResp = AccountResponse<CreateDeviceGrantOTPResponse>.CreateResponse(resp, RequestUrl("/v1/create-device-grant-otp"));

                if (accountResp.IsSuccess) {
                    onReceive.Invoke(accountResp);
                } else {
                    HandleError("GrantDeviceWithOTP", accountResp.Error);
                    onError(resp.Body.ToJson<ErrorResponse>());
                }
            });
        }

        public static void GrantDeviceWithOTP(GrantDeviceWithOTPRequest request, Action<AccountResponse<GrantDeviceWithOTPResponse>> onReceive, Action<ErrorResponse> onError)
        {
            HttpRequest.Post(new HttpRequestOptions
            {
                url = RequestUrl("/v1/grant-device-with-otp"),
                body = request,
                headers = Headers(),
            }, resp =>
            {
                if (resp.IsSuccess) Log.D(resp.ToString());
                else Log.D(resp.ToString());

                var accountResp = AccountResponse<GrantDeviceWithOTPResponse>.CreateResponse(resp, RequestUrl("/v1/grant-device-with-otp"));

                if(accountResp.IsSuccess) {
                    onReceive.Invoke(accountResp);
                }
                else {
                    HandleError("GrantDeviceWithOTP", accountResp.Error);
                    onError(resp.Body.ToJson<ErrorResponse>());
                }
            });
        } 



        private static string RequestUrl(string urlPath)
        {
            return $"{endpoint}{urlPath}";
        }

        private static Dictionary<string, string> Headers()
        {
            return new Dictionary<string, string>()
            {
                {"Accept-Language", I18n.GetLanguageCode()},
                {"x-timestamp-unix", Utils.UnixTimeStamp()},
                {"x-game-id", Config.gameId},
                {"x-game-platform", "windows"},
                {"x-game-distro", Configuration.Instance.Distro},
                {"x-sdk-version", $"combo-sdk-windows/{Version.Version.SDKVersion} combo-sdk-unity/{unitySdkVersion} (unity/{unityVersion})"},
                {"x-bundle-id", string.IsNullOrEmpty(Application.identifier) ? Config.gameId : Application.identifier },
                {"x-bundle-version", Application.version},
                {"x-device-id", Device.UUID},
                {"x-device-name", HttpUtils.UrlEncode(Device.DeviceName)},
                {"x-device-model", HttpUtils.UrlEncode(Device.Model)},
                {"x-os-type", Device.OSType},
                {"x-os-version", Device.OSVersion},
            };
        }

        private static void HandleError(string operationName, InternalError error, bool isShowServerErrorToast = true)
        {
            var serverError = ErrorExtensions.Convert<ServerError>(error);
            var networkError = ErrorExtensions.Convert<NetworkError>(error);
            if(networkError != null)
            {
                UIController.Instance.ShowToast(I18n.T("network_error"));
                Log.I($"Failed to {operationName}, status_code = NetworkError, error = {error.Message}");
            }
            if(serverError != null)
            {
                if (isShowServerErrorToast)
                {
                    UIController.Instance.ShowToast(serverError.ErrorMsg);
                }
                Log.I($"Failed to {operationName}, status_code = ServerError, error = {serverError.Error}, error_message = {serverError.ErrorMsg}");
            }
        }
    }
}