using System.Text;
using UnityEngine;
using System.Collections;
using UnityEngine.Events;
using UnityEngine.Networking;
using System.Collections.Generic;
using MiniJSON;
using Newtonsoft.Json;
using Json = Spine.Json;
using BingoBrain.Core;
using BingoBrain;
using System;
using DontConfuse;



public class NetworkKit
{
    public static string CDNUrl;
    public static string GetCacheToken()
    {
        string token = null;
        if (PlayerPrefsKit.HasKey(PrefsKeyConst.JarvisToken))
        {
            token = PlayerPrefsKit.ReadString(PrefsKeyConst.JarvisToken);
        }

        return token;
    }

    public static void SetCacheToken(string token)
    {
        PlayerPrefsKit.WriteString(PrefsKeyConst.JarvisToken, token);
    }

    private static IEnumerator PostInternal<T>(string url, object requestData, UnityAction<bool, T> onCompleted,
        Dictionary<string, string> header = null)
    {
        var requestJson = SerializeUtil.ToJsonIndented(requestData);

        var url2 = url;
#if BingoBrainRelease
        url2 = Base64Kit.Encode(url);
        requestJson = Base64Kit.Encode(requestJson);
#endif
        var bytes = Encoding.UTF8.GetBytes(requestJson);
        var url1 = BingoBrain.Network.domainUrl + url2;
        //Debug.Log($"Url: {url1}");
        var loginRequest = new UnityWebRequest(url1, UnityWebRequest.kHttpVerbPOST)
        {
            uploadHandler = new UploadHandlerRaw(bytes),
            downloadHandler = new DownloadHandlerBuffer()
        };

        if (header != null)
        {
            foreach (var keyValuePair in header)
            {
                loginRequest.SetRequestHeader(keyValuePair.Key, keyValuePair.Value);
            }
        }

        SetRequestContentType(loginRequest);
        yield return loginRequest.SendWebRequest();
        if (loginRequest.result is not UnityWebRequest.Result.Success)
        {
            onCompleted?.Invoke(false, default);
        }
        else
        {
            var receiveContent = loginRequest.downloadHandler.text;
#if BingoBrainRelease
            if (!receiveContent.IsNullOrWhiteSpace())
            {
                receiveContent = receiveContent.Substring(0, receiveContent.Length - 1);
                receiveContent = receiveContent.Substring(1);
                receiveContent = Base64Kit.Decode(receiveContent);
            }
#endif

           //Debug.Log(url + "--------" + loginRequest.downloadHandler.text);
            //Debug.Log(url + "--------" + receiveContent);
            var response = SerializeUtil.ToObject<ResponseData>(receiveContent);

            if (response?.code == 0)
            {
                var responseData = SerializeUtil.ToObject<T>(response.data.ToString());
                onCompleted?.Invoke(true, responseData);
            }
            else
            {
                if (response?.code == 1005)
                {
                    ReLoginGetToken();
                }

                onCompleted?.Invoke(false, default);
            }


        }

        loginRequest.Dispose();
    }

    public static void SetRequestContentType(UnityWebRequest request)
    {
        request.SetRequestHeader("Content-Type", "application/json;charset=utf-8");
    }

    public static void Post<T>(string url, object requestData, UnityAction<bool, T> onCompleted)
    {
        IsfvKit.StartCoroutine(PostInternal(url, requestData, onCompleted));
    }
    public static void Post(string url, object requestData, UnityAction<bool, object> onCompleted = null)
    {
        IsfvKit.StartCoroutine(PostInternal(url, requestData, onCompleted));
    }

    public static void PostWithHeader<T>(string url, object requestData = null,
        UnityAction<bool, T> onCompleted = null)
    {
        ReSetToken();

        var headers = new Dictionary<string, string> { { "x-token", GetCacheToken() } };
        IsfvKit.StartCoroutine(PostInternal(url, requestData, onCompleted, headers));
    }

    public static void PostWithHeader<T>(string url, UnityAction<bool, T> onCompleted)
    {
        if (onCompleted != null)
        {
            PostWithHeader<T>(url, null, (isSuccess, obj) => { onCompleted.Invoke(isSuccess, obj); });
        }
        else
        {
            PostWithHeader<T>(url);
        }
    }

    public static void PostWithHeader(string url, object requestData = null, UnityAction<bool> onCompleted = null)
    {
        if (onCompleted != null)
        {
            PostWithHeader<object>(url, requestData, (isSuccess, obj) => { onCompleted?.Invoke(isSuccess); });
        }
        else
        {
            PostWithHeader<object>(url, requestData);
        }
    }

    public static void Get(string url, UnityAction<string> onCompleted)
    {
        IsfvKit.StartCoroutine(GetInternal(url, onCompleted));
    }

    public static IEnumerator GetInternal(string url, UnityAction<string> onCompleted)
    {
        var request = UnityWebRequest.Get(url);
        yield return request.SendWebRequest();
        if (request.result is not UnityWebRequest.Result.Success)
        {
            onCompleted?.Invoke(default);
        }
        else
        {
            var receiveContent = request.downloadHandler.text;

            var json = Json_StringFormat(receiveContent);


            onCompleted?.Invoke(receiveContent);
        }

        request.Dispose();
    }
    public static string Json_StringFormat(string sourceJson)
    {
        sourceJson += " ";
        var index = 0;
        var newJson = new StringBuilder();

        for (int i = 0; i < sourceJson.Length - 1; i++)
        {
            if (sourceJson[i] == '{' || sourceJson[i] == '[')
            {
                index++;
                newJson.Append(sourceJson[i]);
                newJson.Append("\n");
                for (var a = 0; a < index; a++)
                {
                    newJson.Append("\t");
                }
            }
            else if ((sourceJson[i] == '}' || sourceJson[i] == ']'))
            {
                index--;
                newJson.Append("\n");
                for (var a = 0; a < index; a++)
                {
                    newJson.Append("\t");
                }

                newJson.Append(sourceJson[i]);
                newJson.Append(sourceJson[i + 1] == ',' ? "," : "");
                newJson.Append("\n");

                if (sourceJson[i + 1] == ',') i++;
                for (int a = 0; a < index; a++)
                {
                    newJson.Append("\t");
                }
            }
            else if (sourceJson[i] != '}' && sourceJson[i] != ']' && sourceJson[i + 1] == ',')
            {
                newJson.Append(sourceJson[i]);
                newJson.Append(sourceJson[i + 1]);
                newJson.Append("\n");
                i++;
                for (var a = 0; a < index; a++)
                {
                    newJson.Append("\t");
                }
            }
            else
            {
                newJson.Append(sourceJson[i]);
            }
        }

        return newJson.ToString();
    }
    public static void BuriedPoint(string eventname, string eventproperty, int integer)
    {

        if(eventname == BuriedPointEvent.Apple_AD_event || eventname == BuriedPointEvent.Apple_pay_event)
        {    
            eventname = GameHelper.IsAdModelOfPay()?BuriedPointEvent.Apple_AD_event:BuriedPointEvent.Apple_pay_event;
        }

        buriedPointObject.@event = eventname;
        buriedPointObject.property = eventproperty;
        buriedPointObject.n = integer;
        PostWithHeader<BuriedPointObject>("/event/incrN", buriedPointObject, (isSuccess, obj) =>
        {
            // Debug.Log(isSuccess);
            // Debug.Log(eventproperty);
            //Debug.Log(JsonUtility.ToJson(obj));
        });
    }
    public static BuriedPointObject buriedPointObject = new BuriedPointObject();

     public static string GetNetworkType()
    {
        switch (Application.internetReachability)
        {
            case NetworkReachability.ReachableViaCarrierDataNetwork:
                return NetworkType.mobile;
            case NetworkReachability.ReachableViaLocalAreaNetwork:
                return NetworkType.wifi;
            case NetworkReachability.NotReachable:
                return NetworkType.notConnected;
            default: 
                return NetworkType.notConnected;
        }
    }

    private static bool isReqToken = false;
    public static void ReSetToken()
    {
        if (isReqToken) return;

        var nowTimes = GameHelper.GetNowTime();
        var passtime = GameHelper.GetLoginModel().expires_at;
        // Debug.Log($"ReSetToken nowTimes:{nowTimes} passtime:{passtime}");
        if (passtime == 0 || passtime - nowTimes > 3600) return;

        isReqToken = true;

        var headers = new Dictionary<string, string> { { "x-token", GetCacheToken() } };

        IsfvKit.StartCoroutine(PostInternal<ResquestTokenData>("tokenRefresh", null,  (isSuccess, tokenData) =>
        {
            if (isSuccess)
            {
                LoginModel loginModel = GameHelper.GetLoginModel();
                loginModel.token = tokenData.token;
                loginModel.expires_at = tokenData.expires_at;
                
                SetCacheToken(tokenData.token);
            }
            isReqToken = false;
            
        }, headers));
    }


    private static bool isReqToken1 = false;

    public static void ReLoginGetToken() 
    {
        if (isReqToken1) return;

        var requestLoginData = new RequestLoginData
        {
            device_id = SystemInfo.deviceUniqueIdentifier,
            pack_name = NetworkMsg.Identifier,
            app_version = Application.version,
            channel = BingoBea.Instance.attribution,
            sim = WebviewManager.haveSimCard

        };
        isReqToken1 = true;


        Post<LoginModel>("login", requestLoginData, (isSuccess, loginData) =>{
            if (isSuccess)
            {
                LoginModel loginModel = GameHelper.GetLoginModel();
                loginModel.token = loginData.token;
                loginModel.expires_at = loginData.expires_at;
                
                SetCacheToken(loginData.token);
            }

            isReqToken1 = false;
        });
    }

}
public class Base64Kit
{
    public static string Base64Encode(string source)
    {
        byte[] bytes = Encoding.UTF8.GetBytes(source);
        string encode = Convert.ToBase64String(bytes);
        return encode;
    }
    public static string Encode(string data, bool is_apple_pay = false)
    {
        var key = BingoBrain.Network.DomainRelease;
        //if (is_apple_pay) key = "com.leisuregames.crazygourmet";

        var keyMD5 = MD5Kit.MD5String1(key);
        //UnityEngine.Debug.Log("Base64 Encode Key: " + keyMD5);
        var str = Base64EncodeUtil.Base64Encode(data + keyMD5);

        var bytes = Encoding.UTF8.GetBytes(str);
        for (int i = 0, j = bytes.Length - 1; i < j; i += 1, j -= 1)
        {
            if (i % 2 == 0)
            {
                (bytes[i], bytes[j]) = (bytes[j], bytes[i]);
            }
        }

        var loginData = Encoding.UTF8.GetString(bytes);
        return loginData;
    }

    public static string Decode(string data)
    {
        var bytes = Encoding.UTF8.GetBytes(data);
        for (int i = 0, j = bytes.Length - 1; i < j; i += 1, j -= 1)
        {
            if (i % 2 == 0)
            {
                (bytes[i], bytes[j]) = (bytes[j], bytes[i]);
            }
        }

        var str = Encoding.UTF8.GetString(bytes);
        var str1 = Base64EncodeUtil.Base64Decode(str);
        var key = BingoBrain.Network.DomainRelease;
        var keyMD5 = MD5Kit.MD5String1(key);
        // Debug.Log("Base64 Decode Key: " + keyMD5);
        // Debug.Log("Base64 Decode str1: " + str1);
        var result = str1.Replace(keyMD5, string.Empty);
        return result;
    }

    public static string Decode(string data, string key)
    {
        var bytes = Encoding.UTF8.GetBytes(data);
        for (int i = 0, j = bytes.Length - 1; i < j; i += 1, j -= 1)
        {
            if (i % 2 == 0)
            {
                (bytes[i], bytes[j]) = (bytes[j], bytes[i]);
            }
        }

        var str = Encoding.UTF8.GetString(bytes);
        var str1 = Base64EncodeUtil.Base64Decode(str);
        // var key = NetworkManager.DomainRelease;
        var keyMD5 = MD5Kit.MD5String1(key);
        var result = str1.Replace(keyMD5, string.Empty);
        return result;
    }
}

public class ResquestTokenData
{
    public string token;
    public long expires_at;
}
public class NetworkType
{
    public static string mobile = "Mobile Data";
    public static string wifi = "Wi-Fi";
    public static string notConnected = "Not Connected";
}
public static class Base64EncodeUtil
{
    public static string Base64Encode(string source)
    {
        return Base64Encode(Encoding.UTF8, source);
    }

    public static string Base64Decode(string result)
    {
        return Base64Decode(Encoding.UTF8, result);
    }




    public static string Base64Encode(Encoding encoding, string source)
    {
        byte[] bytes = encoding.GetBytes(source);
        string encode = Convert.ToBase64String(bytes);
        return encode;
    }




    public static string Base64Decode(Encoding encoding, string result)
    {
        byte[] bytes = Convert.FromBase64String(result);
        string decode = encoding.GetString(bytes);
        return decode;
    }




    public static string Base64EncodeString(byte[] source)
    {
        return Convert.ToBase64String(source);
    }




    public static byte[] Base64DecodeBytes(string result)
    {
        return Convert.FromBase64String(result);
    }
}
public class ResponseData
{
    public int code;
    public string msg;
    public object data;
}
public class BuriedPointObject
{
    public string @event;
    public string property;
    public int n;
}
public class BuriedPointEvent
{
        public static string play_event = "Number_of_people_play";
        public static string play_property = "Number_of_people_playing";

        public static string playing_event = "Playing_time";
        public static string playing_property = "Room_type";

        public static string ad_task = "ad_task";
        public static string watch_ad_number = "watch_ad_number";
        public static string finish_ad_number = "finish_ad_number";

        public static string h5_event = "H5_task";
        public static string h5_event_time = "H5_time";
        public static string h5_event_numbers = "finish_H5_number";

        public static string withdraw_behavior = "withdraw_behavior";
        public static string withdraw_message = "withdraw_message";
        public static string withdraw_cash1 = "withdraw_cash1";
        public static string withdraw_cash2 = "withdraw_cash2";
        public static string withdraw_cash3 = "withdraw_cash3";

        public static string Hall_behavior = "Hall_behavior";
        public static string open_hall_number = "open_hall_number";
        //public static string open_hall_people = "open_hall_people";
        public static string collect_fly_number = "collect_fly_number";
        //public static string collect_fly_people = "collect_fly_people";
        public static string fly_ct_number = "fly_ct_number";
        //public static string fly_ct_people = "fly_ct_people";
        public static string annular_finish_number = "annular_finish_number";
        public static string annular_get_number = "annular_get_number";
        public static string annular_ct_number = "annular_ct_number";
        //public static string annular_ct_people = "annular_ct_people";

        public static string video_behavior = "video_behavior";
        public static string watch_ad_people = "watch_ad_people";
        public static string watch_success_ad_people = "watch_success_ad_people";

        public static string video_type = "video_type";
        public static string Rewarded_videos_trigger_number = "Rewarded_videos_trigger_number";
        public static string Rewarded_videos_fill_number = "Rewarded_videos_fill_number";
        public static string Rewarded_videos_dinish_number = "Rewarded_videos_dinish_number";
        public static string Interstitial_videos_trigger_number = "Interstitial_videos_trigger_number";
        public static string Interstitial_videos_fill_number = "Interstitial_videos_fill_number";
        public static string Interstitial_videos_dinish_number = "Interstitial_videos_dinish_number";
        public static string Apple_pay_event = "Pay_Event";
        public static string Apple_AD_event = "AD_Event";


        public static string pack_show = "pack_show";
        public static string pack_click = "pack_click";
        public static string pack_open = "pack_open";
        public static string pack_success = "pack_success";

        public static string remove_ad_show = "remove_ad_show";
        public static string remove_ad_click = "remove_ad_click";
        public static string remove_ad_open = "remove_ad_open";
        public static string remove_ad_success = "remove_ad_success";


        public static string pass_show = "master_pass_show";
        public static string pass_click = "master_pass_click";
        public static string pass_open = "pass_open";
        public static string pass_success = "master_pass_receive";

        public static string buy_one_show = "buy_one_show";
        public static string buy_one_click = "buy_one_click";
        public static string buy_one_open = "buy_one_open";
        public static string buy_one_success = "buy_one_success";

        public static string gold_show = "shop_show";
        public static string gold_click_1 = "shop_click";

        public static string gold_click_ad = "gold_click_ad";

        // public static string gold_click_2 = "gold_click_2";
        // public static string gold_click_3 = "gold_click_3";
        // public static string gold_click_4 = "gold_click_4";
        // public static string gold_open_1 = "gold_open_1";
        // public static string gold_open_2 = "gold_open_2";
        // public static string gold_open_3 = "gold_open_3";
        // public static string gold_open_4 = "gold_open_4";
        public static string gold_success_1 = "shop_receive";
        // public static string gold_success_2 = "gold_success_2";
        // public static string gold_success_3 = "gold_success_3";
        // public static string gold_success_4 = "gold_success_4";
        public static string afterRewardAdShow = "afterRewardAdShow";
        public static string afterRewardAdEnd = "afterRewardAdEnd";
                public static string fail_show = "fail_show";
        public static string fail_click = "fail_click";
        public static string fail_buy_success = "fail_buy_success";
                public static string three_days_gift_show = "three_days_gift_show";
        public static string three_days_gift_click = "three_days_gift_click";
        public static string three_days_gift_buy_success = "three_days_gift_buy_success";
        public static string three_days_gift_open = "three_days_gift_open";
        public static string three_day1_success = "three_day1_success";
        public static string three_day2_success = "three_day2_success";
        public static string three_day3_success = "three_day3_success";
         public static string Three_days_gift_event = "Three_days_gift_event";
}
