using System;
using System.Reflection;
using System.Threading.Tasks;
using _Combo;

namespace _Core
{
    internal static class TapTapInit
    {
        public static Type tapTapInitType = Assembly.Load("TapSDK.Core.Runtime").GetType("TapSDK.Core.TapTapSDK");
        public static Type tapTapSdkOptionsType = Assembly.Load("TapSDK.Core.Runtime").GetType("TapSDK.Core.TapTapSdkOptions");
        public static Type tapTapSdkBaseOptionsType = Assembly.Load("TapSDK.Core.Runtime").GetType("TapSDK.Core.TapTapSdkBaseOptions");
        public static Type tapTapComplianceOptionType = Assembly.Load("TapSDK.Compliance").GetType("TapSDK.Compliance.TapTapComplianceOption");

        public static void Init(string clientId, string clientToken, bool showSwitchAccount, bool useAgeRange, string clientPublicKey = "")
        {
            if (tapTapInitType == null)
            {
                Log.W("Failed to get type TapTapSDK");
            }
            else
            {
                MethodInfo methodWithTwoParams = tapTapInitType.GetMethod(
                    "Init",
                    BindingFlags.Static | BindingFlags.Public,
                    null,
                    new Type[] { tapTapSdkOptionsType, tapTapSdkBaseOptionsType.MakeArrayType() },
                    null);

                if (methodWithTwoParams != null)
                {
                    try
                    {
                        object tapTapSdkOptionsInstance = Activator.CreateInstance(tapTapSdkOptionsType);

                        Array tapTapBaseOptionsArrayInstance = Array.CreateInstance(tapTapSdkBaseOptionsType, 1);

                        object tapTapComplianceOptionInstance = Activator.CreateInstance(tapTapComplianceOptionType);
                        tapTapBaseOptionsArrayInstance.SetValue(tapTapComplianceOptionInstance, 0);

                        if (tapTapSdkOptionsInstance != null && tapTapBaseOptionsArrayInstance != null)
                        {
                            FieldInfo clientIdProperty = tapTapSdkOptionsType.GetField("clientId");
                            FieldInfo clientTokenProperty = tapTapSdkOptionsType.GetField("clientToken");

                            if (clientIdProperty != null && clientTokenProperty != null)
                            {
                                clientIdProperty.SetValue(tapTapSdkOptionsInstance, clientId);
                                clientTokenProperty.SetValue(tapTapSdkOptionsInstance, clientToken);

                                if (!string.IsNullOrEmpty(clientPublicKey))
                                {
                                    FieldInfo clientPublicKeyProperty = tapTapSdkOptionsType.GetField("clientPublicKey");
                                    clientPublicKeyProperty.SetValue(tapTapSdkOptionsInstance, clientPublicKey);
                                }
                            }
                            else
                            {
                                Log.E("Failed to get properties of TapTapSdkOptions.");
                                return;
                            }

                            FieldInfo showSwitchAccountProperty = tapTapComplianceOptionType.GetField("showSwitchAccount");
                            FieldInfo useAgeRangeProperty = tapTapComplianceOptionType.GetField("useAgeRange");

                            if (showSwitchAccountProperty != null && useAgeRangeProperty != null)
                            {
                                showSwitchAccountProperty.SetValue(tapTapComplianceOptionInstance, showSwitchAccount);
                                useAgeRangeProperty.SetValue(tapTapComplianceOptionInstance, useAgeRange);
                            }
                            else
                            {
                                Log.E("Failed to get properties of TapTapComplianceOption.");
                                return;
                            }

                            methodWithTwoParams.Invoke(null, new object[] { tapTapSdkOptionsInstance, tapTapBaseOptionsArrayInstance });
                            Log.I("Method Init invoked successfully.");
                        }
                    }
                    catch (Exception e)
                    {
                        Log.E(e);
                    }
                }
                else
                {
                    Console.WriteLine("Failed to find Init method.");
                }
            }
        }

        public async static Task IsLaunchedFromTapTapPC(Action<bool> onSuccess, Action<InternalError> onError)
        {
            if (tapTapInitType == null)
            {
                Log.W("Failed to get type tapTapInitType");
                onError?.Invoke(new InternalError("Failed to get type for tapTapInitType", new InitializedError(InitializedErrorType.INIT_FAILED)));
                return;
            }

            try
            {
                MethodInfo isLaunchedFromTapTapPCMethod = tapTapInitType.GetMethod(
                    "IsLaunchedFromTapTapPC",
                    BindingFlags.Static | BindingFlags.Public
                );

                if (isLaunchedFromTapTapPCMethod != null)
                {
                    var resultTask = (Task<bool>)isLaunchedFromTapTapPCMethod.Invoke(null, null);
                    if (resultTask == null)
                    {
                        Log.E("IsLaunchedFromTapTapPC result is null");
                        onError(new InternalError("IsLaunchedFromTapTapPC result is null", new InitializedError(InitializedErrorType.INIT_FAILED)));
                        return;
                    }
                    bool result = await resultTask;

                    onSuccess(result);
                }
                else
                {
                    Log.E("IsLaunchedFromTapTapPC method not found.");
                    onError(new InternalError("IsLaunchedFromTapTapPC method not found.", new InitializedError(InitializedErrorType.INIT_FAILED)));
                }
            }
            catch (Exception ex)
            {
                Log.E($"An exception occurred: {ex.Message}");
                onError(new InternalError($"An exception occurred: {ex.Message}", new InitializedError(InitializedErrorType.INIT_FAILED)));
            }
        }

    }
}