#if UNITY_IOS

using System.Runtime.InteropServices;
using UnityEngine;
using System;
using Newtonsoft.Json;
using System.Collections.Generic;

using ThinkingData.Analytics;
using Sentry;

namespace Combo.Platform
{
    public class NativeIOS: MonoBehaviour
    {

        private static Action<Result<SetupResult>> setupFinishedAction;
        private static Action<Result<LoginResult>> loginFinishedAction;
        private static Action<Result<LogoutResult>> logoutFinishedAction;
        private static Action<Result<PurchaseResult>> purchaseFinishedAction;
        private static Action<Result<PreloadAdResult>> preloadAdFinishedAction;
        private static Action<Result<ShowAdResult>> showAdFinishedAction;
        private static Action<Result<ShareResult>> shareFinishedAction;
        private static Action<Result<KickOutResult>> kickOutFinishedAction;
        private static Action<Result<DownloadUrlResult>> getDownloadUrlFinishedAction;
        private static Action<Result<OpenShortLinkResult>> openShortLinkFinishedAction;
        private static Action<Result<CheckAnnouncementsResult>> checkAnnouncementsFinishedAction;
        private static Action<Result<OpenAnnouncementsResult>> openAnnouncementsFinishedAction;
        private static Action<Result<GetAnnouncementsResult>> getAnnouncementsFinishedAction;
        private static Action<Result<ComplainResult>> complainFinishedAction;
        private static Action<Result<RedeemGiftCodeResult>> redeemGiftCodeFinishedAction;

        [DllImport("__Internal")]
        private static extern int combo_sdk_setup(string strJsonData);
        public static void Setup(SetupOptions opts, Action<Result<SetupResult>> callback) {
            GameObject obj = GameObject.Find("ComboSDKIOS");

            if (obj == null)
            {
                obj = new GameObject("ComboSDKIOS", typeof(NativeIOS));
                GameObject.DontDestroyOnLoad(obj);
            }
            setupFinishedAction = callback;
            combo_sdk_setup(opts.ToJson());
        }
        
        [DllImport("__Internal")]
        private static extern int combo_sdk_login();
        public static void Login(Action<Result<LoginResult>> callback) {
            if (!Application.isPlaying) { return; }

            loginFinishedAction = callback;

            combo_sdk_login();
        }

        [DllImport("__Internal")]
        private static extern int combo_sdk_logout();
        public static void Logout(Action<Result<LogoutResult>> callback)
        {
            if (!Application.isPlaying) { return; }

            logoutFinishedAction = callback;
            combo_sdk_logout();
        }

        [DllImport("__Internal")]
        private static extern int combo_sdk_purchase(string strJsonData);
        public static void Purchase(PurchaseOptions otps, Action<Result<PurchaseResult>> callback)
        {
            if (!Application.isPlaying) { return; }

            purchaseFinishedAction = callback;
            combo_sdk_purchase(otps.ToJson());
        }

        [DllImport("__Internal")]
        private static extern System.IntPtr combo_sdk_getUserInfo();
        public static LoginInfo GetLoginInfo()
        {
            if (!Application.isPlaying) { return null; }

            var userInfoPtr = combo_sdk_getUserInfo();
            string userInfo = Marshal.PtrToStringAnsi(userInfoPtr);
            // free memory for C
            Marshal.FreeHGlobal(userInfoPtr);
            if (userInfo == null) return null;
            return Result<LoginInfo>.CreateSuccessFromJson(userInfo).Data;
        }

        [DllImport("__Internal")]
        public static extern int combo_sdk_preloadAd(string strJsonData);
        public static void PreloadAd(PreloadAdOptions opts, Action<Result<PreloadAdResult>> callback)
        {
            if (!Application.isPlaying) { return; }

            preloadAdFinishedAction = callback;
            DebugLog(opts.ToJson());
            combo_sdk_preloadAd(opts.ToJson());
        }

        [DllImport("__Internal")]
        public static extern int combo_sdk_showAd(string strJsonData);
        public static void ShowAd(ShowAdOptions opts, Action<Result<ShowAdResult>> callback)
        {
            if (!Application.isPlaying) { return; }

            showAdFinishedAction = callback;
            DebugLog(opts.ToJson());
            combo_sdk_showAd(opts.ToJson());
        }

        [DllImport("__Internal")]
        public static extern int combo_sdk_share(string type, string strJsonData);
        public static void Share(ShareOptions opts, Action<Result<ShareResult>> callback)
        {
            if (!Application.isPlaying) { return; }

            shareFinishedAction = callback;
            combo_sdk_share(opts.GetType().Name, opts.ToJson());
        }

        [DllImport("__Internal")]
        public static extern System.IntPtr combo_sdk_getVersion();
        public static string GetVersion()
        {
            if (!Application.isPlaying) { return null; }

            var ptr = combo_sdk_getVersion();
            string versionInfo = Marshal.PtrToStringAnsi(ptr);
            // free memory for C
            Marshal.FreeHGlobal(ptr);
            return versionInfo;
        }

        [DllImport("__Internal")]
        public static extern System.IntPtr combo_sdk_getDistro();
        public static string GetDistro()
        {
            if (!Application.isPlaying) { return null; }

            var ptr = combo_sdk_getDistro();
            string distro = Marshal.PtrToStringAnsi(ptr);
            // free memory for C
            Marshal.FreeHGlobal(ptr);
            return distro;
        }

        [DllImport("__Internal")]
        public static extern System.IntPtr combo_sdk_getParameters();
        public static Dictionary<string, string> GetParameters()
        {
            if (!Application.isPlaying) { return null; }
            
            var ptr = combo_sdk_getParameters();
            string parameters = Marshal.PtrToStringAnsi(ptr);
            // free memory for C
            Marshal.FreeHGlobal(ptr);
            Dictionary<string, string> dict = JsonConvert.DeserializeObject<Dictionary<string, string>>(parameters);
            return dict;
        }

        [DllImport("__Internal")]
        public static extern System.IntPtr combo_sdk_getDeviceId();
        public static string GetDeviceId() {
            if (!Application.isPlaying) { return null; }

            var ptr = combo_sdk_getDeviceId();
            string deviceId = Marshal.PtrToStringAnsi(ptr);
            // free memory for C
            Marshal.FreeHGlobal(ptr);
            return deviceId;
        }

        [DllImport("__Internal")]
        public static extern System.IntPtr combo_sdk_openAppSettings();
        public static void OpenAppSettings() {
            if (!Application.isPlaying) { return; }

            combo_sdk_openAppSettings();
        }

        [DllImport("__Internal")]
        public static extern System.IntPtr combo_sdk_getUserId();
        public static string GetUserId() {
            if (!Application.isPlaying) { return null; }

            var ptr = combo_sdk_getUserId();
            string uid = Marshal.PtrToStringAnsi(ptr);
            // free memory for C
            Marshal.FreeHGlobal(ptr);
            return uid;
        }

        [DllImport("__Internal")]
        public static extern System.IntPtr combo_sdk_manageAccount();
        public static void ManageAccount() {
            if (!Application.isPlaying) { return; }

            combo_sdk_manageAccount();
        }

        [DllImport("__Internal")]
        public static extern System.IntPtr combo_sdk_deleteAccount();
        public static void DeleteAccount() {
            if (!Application.isPlaying) { return; }

            combo_sdk_deleteAccount();
        }

        [DllImport("__Internal")]
        public static extern System.IntPtr combo_sdk_changePassword();
        public static void ChangePassword() {
            if (!Application.isPlaying) { return; }

            combo_sdk_changePassword();
        }

        [DllImport("__Internal")]
        public static extern System.IntPtr combo_sdk_contactSupport();
        public static void ContactSupport() {
            if (!Application.isPlaying) { return; }

            combo_sdk_contactSupport();
        }

        [DllImport("__Internal")]
        public static extern bool combo_sdk_isFeatureAvailable(string strJsonData);
        public static bool IsFeatureAvailable(Feature feature) {
            if (!Application.isPlaying) { return false; }
            
            string featureName = Enum.GetName(typeof(Feature), feature);
            return combo_sdk_isFeatureAvailable(featureName);
        }

        [DllImport("__Internal")]
        public static extern System.IntPtr combo_sdk_openGameUrlWithController(string strJsonData);
        public static void OpenGameUrl(GameUrl url) {
            if (!Application.isPlaying) { return; }
            
            string gameUrl = Enum.GetName(typeof(GameUrl), url);
            combo_sdk_openGameUrlWithController(gameUrl);
        }

        [DllImport("__Internal")]
        public static extern int combo_sdk_getDownloadUrl();
        public static void GetDownloadUrl(Action<Result<DownloadUrlResult>> callback)
        {
            if (!Application.isPlaying) { return; }

            getDownloadUrlFinishedAction = callback;
            combo_sdk_getDownloadUrl();
        }

        [DllImport("__Internal")]
        public static extern IntPtr combo_sdk_getAvailableShareTargets(out int count);
        public static ShareTarget[] GetAvailableShareTargets()
        {
            if (!Application.isPlaying) { return new ShareTarget[]{ ShareTarget.SYSTEM }; }

            int count;
            IntPtr ptr = combo_sdk_getAvailableShareTargets(out count);
            int[] targetsArray = new int[count];
            Marshal.Copy(ptr, targetsArray, 0, targetsArray.Length);

            // 将整数数组转换为 ShareTarget 枚举数组
            ShareTarget[] shareTargets = new ShareTarget[targetsArray.Length];
            for (int i = 0; i < targetsArray.Length; i++)
            {
                shareTargets[i] = (ShareTarget)targetsArray[i];
            }

            Marshal.FreeHGlobal(ptr);

            return shareTargets;
        }

        [DllImport("__Internal")]
        public static extern IntPtr combo_sdk_openShortLink(string shortLink, string gameData);
        public static void OpenShortLink(string shortLink, Dictionary<string, string> gameData, Action<Result<OpenShortLinkResult>> callback)
        {
            if (!Application.isPlaying) { return; }

            openShortLinkFinishedAction = callback;
            string gameDataStr = JsonConvert.SerializeObject(gameData);
            combo_sdk_openShortLink(shortLink, gameDataStr);
        }

        [DllImport("__Internal")]
        public static extern IntPtr combo_sdk_checkAnnouncements(string strJsonData);
        public static void CheckAnnouncements(CheckAnnouncementsOptions opts, Action<Result<CheckAnnouncementsResult>> callback)
        {
            if (!Application.isPlaying) { return; }

            checkAnnouncementsFinishedAction = callback;
            combo_sdk_checkAnnouncements(opts.ToJson());
        }

        [DllImport("__Internal")]
        public static extern IntPtr combo_sdk_openAnnouncements(string strJsonData);
        public static void OpenAnnouncements(OpenAnnouncementsOptions opts, Action<Result<OpenAnnouncementsResult>> callback)
        {
            if (!Application.isPlaying) { return; }

            openAnnouncementsFinishedAction = callback;
            combo_sdk_openAnnouncements(opts.ToJson());
        }

        // 调用 iOS 原生 GetAnnouncements，结果通过 _GetAnnouncementsSucceed/Failed 回调返回
        [DllImport("__Internal")]
        public static extern IntPtr combo_sdk_getAnnouncements(string strJsonData);
        public static void GetAnnouncements(GetAnnouncementsOptions opts, Action<Result<GetAnnouncementsResult>> callback)
        {
            if (!Application.isPlaying) { return; }

            Debug.Log($"[NativeIOS] GetAnnouncements: profile={opts.Profile} level={opts.Level}");
            getAnnouncementsFinishedAction = callback;
            combo_sdk_getAnnouncements(opts.ToJson());
        }

        [DllImport("__Internal")]
        public static extern IntPtr combo_sdk_complain(string strJsonData);
        public static void Complain(ComplainOptions opts, Action<Result<ComplainResult>> callback)
        {
            if (!Application.isPlaying) { return; }

            complainFinishedAction = callback;
            combo_sdk_complain(opts.ToJson());
        }

        [DllImport("__Internal")]
        public static extern IntPtr combo_sdk_redeemGiftCode(string strJsonData);
        public static void RedeemGiftCode(RedeemGiftCodeOptions opts, Action<Result<RedeemGiftCodeResult>> callback)
        {
            if (!Application.isPlaying) { return; }

            redeemGiftCodeFinishedAction = callback;
            combo_sdk_redeemGiftCode(opts.ToJson());
        }

        public static void OnKickOut(Action<Result<KickOutResult>> callback)
        {
            kickOutFinishedAction = callback;
        }

        [DllImport("__Internal")]
        public static extern int combo_sdk_getLanguagePreference();

        public static LanguagePreference GetLanguagePreference() {
            if (!Application.isPlaying) { return LanguagePreference.FollowSystem; }

            int perference = combo_sdk_getLanguagePreference();
            Debug.Log($"{perference}");
            
            LanguagePreference languagePreference = (LanguagePreference)perference;

            return languagePreference;
        }


        [DllImport("__Internal")]
        public static extern System.IntPtr combo_sdk_setLanguagePreference(string strJsonData);
        public static void SetLanguagePreference(LanguagePreference languagePreference) {
            if (!Application.isPlaying) { return; }
            
            string perference = Enum.GetName(typeof(LanguagePreference), languagePreference);
            combo_sdk_setLanguagePreference(perference);
        }

        [DllImport("__Internal")]
        public static extern System.IntPtr combo_sdk_getLanguageCode();
        public static string GetLanguageCode() {
            if (!Application.isPlaying) { return null; }

            var ptr = combo_sdk_getLanguageCode();
            string languageCode = Marshal.PtrToStringAnsi(ptr);
            // free memory for C
            Marshal.FreeHGlobal(ptr);
            return languageCode;
        }

        [DllImport("__Internal")]
        public static extern bool combo_sdk_resetGuest();
        public static bool ResetGuest() {
            if (!Application.isPlaying) { return false; }
            return combo_sdk_resetGuest();
        }

        [DllImport("__Internal")]
        public static extern System.IntPtr combo_sdk_reportDouyinCustomEvent(string eventName, string eventParams);
        public static void ReportDouyinCustomEvent(string eventName, Dictionary<string, string> eventParams)
        {
            if (!Application.isPlaying) { return; }

            string parametersStr = JsonConvert.SerializeObject(eventParams);
            combo_sdk_reportDouyinCustomEvent(eventName, parametersStr);
        }

#region From UnitySendMessage (OC Callback)
        public void _SetupSucceed(string msg)
        {
            DebugLog(msg);
            var result = Result<SetupResult>.CreateSuccessFromJson(msg);
            setupFinishedAction?.Invoke(result);
        }

        public void _SetupFailed(string msg)
        {
            DebugLog(msg);
            var result = Result<SetupResult>.CreateFailFromJson(msg);
            setupFinishedAction?.Invoke(result);
        }

        public void _LoginSucceed(string msg)
        {
            DebugLog(msg);
            var result = Result<LoginResult>.CreateSuccessFromJson(msg);
            DebugLog(result.Data.loginInfo.comboId);

            if (result != null) {
                var comboId = result.Data.loginInfo.comboId;
                TDAnalytics.Login(comboId);
                SentrySdk.ConfigureScope(scope =>
                {
                    scope.User.Id = comboId;
                });
            }

            loginFinishedAction?.Invoke(result);
        }

        public void _LoginFailed(string msg)
        {
            DebugLog(msg);
            var result = Result<LoginResult>.CreateFailFromJson(msg);
            loginFinishedAction?.Invoke(result);
        }

        public void _LogoutSucceed(string msg)
        {
            DebugLog(msg);
            TDAnalytics.Logout();
            var result = Result<LogoutResult>.CreateSuccessFromJson(msg);
            logoutFinishedAction?.Invoke(result);
        }

        public void _LogoutFailed(string msg)
        {
            DebugLog(msg);
            var result = Result<LogoutResult>.CreateFailFromJson(msg);
            logoutFinishedAction?.Invoke(result);
        }

        public void _PurchaseSucceed(string msg)
        {
            DebugLog(msg);
            var result = Result<PurchaseResult>.CreateSuccessFromJson(msg);
            purchaseFinishedAction?.Invoke(result);
        }

        public void _PurchaseFailed(string msg)
        {
            DebugLog(msg);
            var result = Result<PurchaseResult>.CreateFailFromJson(msg);
            purchaseFinishedAction?.Invoke(result);
        }

        public void _PreloadAdSucceed(string msg)
        {
            DebugLog(msg);
            var result = Result<PreloadAdResult>.CreateSuccessFromJson(msg);
            preloadAdFinishedAction?.Invoke(result);
        }

        public void _PreloadAdFailed(string msg)
        {
            DebugLog(msg);
            var result = Result<PreloadAdResult>.CreateFailFromJson(msg);
            preloadAdFinishedAction?.Invoke(result);
        }

        public void _ShowAdSucceed(string msg)
        {
            DebugLog(msg);
            var result = Result<ShowAdResult>.CreateSuccessFromJson(msg);
            showAdFinishedAction?.Invoke(result);
        }

        public void _ShowAdFailed(string msg)
        {
            DebugLog(msg);
            var result = Result<ShowAdResult>.CreateFailFromJson(msg);
            showAdFinishedAction?.Invoke(result);
        }

        public void _ShareSucceed(string msg)
        {
            DebugLog(msg);
            var result = Result<ShareResult>.CreateSuccessFromJson(msg);
            shareFinishedAction?.Invoke(result);
        }

        public void _ShareFailed(string msg)
        {
            DebugLog(msg);
            var result = Result<ShareResult>.CreateFailFromJson(msg);
            shareFinishedAction?.Invoke(result);
        }

        public void _KickOutSucceed(string msg)
        {
            DebugLog(msg);
            var result = Result<KickOutResult>.CreateSuccessFromJson(msg);
            kickOutFinishedAction?.Invoke(result);
        }

        public void _GetDownloadUrlSucceed(string msg)
        {
            DebugLog(msg);
            var result = Result<DownloadUrlResult>.CreateSuccessFromJson(msg);
            getDownloadUrlFinishedAction?.Invoke(result);
        }

        public void _GetDownloadUrlFailed(string msg)
        {
            DebugLog(msg);
            var result = Result<DownloadUrlResult>.CreateFailFromJson(msg);
            getDownloadUrlFinishedAction?.Invoke(result);
        }

        public void _OpenShortLinkSucceed(string msg)
        {
            DebugLog(msg);
            var result = Result<OpenShortLinkResult>.CreateSuccessFromJson(msg);
            openShortLinkFinishedAction?.Invoke(result);
        }

        public void _OpenShortLinkFailed(string msg)
        {
            DebugLog(msg);
            var result = Result<OpenShortLinkResult>.CreateFailFromJson(msg);
            openShortLinkFinishedAction?.Invoke(result);
        }

        public void _CheckAnnouncementsSucceed(string msg)
        {
            DebugLog(msg);
            var result = Result<CheckAnnouncementsResult>.CreateSuccessFromJson(msg);
            checkAnnouncementsFinishedAction?.Invoke(result);
        }

        public void _CheckAnnouncementsFailed(string msg)
        {
            DebugLog(msg);
            var result = Result<CheckAnnouncementsResult>.CreateFailFromJson(msg);
            checkAnnouncementsFinishedAction?.Invoke(result);
        }

        public void _OpenAnnouncementsSucceed(string msg)
        {
            DebugLog(msg);
            var result = Result<OpenAnnouncementsResult>.CreateSuccessFromJson(msg);
            openAnnouncementsFinishedAction?.Invoke(result);
        }

        public void _OpenAnnouncementsFailed(string msg)
        {
            DebugLog(msg);
            var result = Result<OpenAnnouncementsResult>.CreateFailFromJson(msg);
            openAnnouncementsFinishedAction?.Invoke(result);
        }

        // ObjC 桥接回调：GetAnnouncements 成功
        public void _GetAnnouncementsSucceed(string msg)
        {
            DebugLog(msg);
            var result = Result<GetAnnouncementsResult>.CreateSuccessFromJson(msg);
            getAnnouncementsFinishedAction?.Invoke(result);
        }

        // ObjC 桥接回调：GetAnnouncements 失败
        public void _GetAnnouncementsFailed(string msg)
        {
            DebugLog(msg);
            var result = Result<GetAnnouncementsResult>.CreateFailFromJson(msg);
            getAnnouncementsFinishedAction?.Invoke(result);
        }

        public void _ComplainSucceed(string msg)
        {
            DebugLog(msg);
            var result = Result<ComplainResult>.CreateSuccessFromJson(msg);
            complainFinishedAction?.Invoke(result);
        }

        public void _ComplainFailed(string msg)
        {
            DebugLog(msg);
            var result = Result<ComplainResult>.CreateFailFromJson(msg);
            complainFinishedAction?.Invoke(result);
        }

        public void _RedeemGiftCodeSucceed(string msg)
        {
            DebugLog(msg);
            var result = Result<RedeemGiftCodeResult>.CreateSuccessFromJson(msg);
            redeemGiftCodeFinishedAction?.Invoke(result);
        }

        public void _RedeemGiftCodeFailed(string msg)
        {
            DebugLog(msg);
            var result = Result<RedeemGiftCodeResult>.CreateFailFromJson(msg);
            redeemGiftCodeFinishedAction?.Invoke(result);
        }
        
        private static void DebugLog(string msg) {
            //Debug.LogWarning("ComboSDKIOS: " + msg);
        }
#endregion
    }
}

#endif

