using System;
using System.Collections.Generic;
using System.Threading.Tasks;
#if UNITY_WEBGL && !UNITY_EDITOR
using System.Runtime.InteropServices;
#endif
using UnityEngine;
#if UNITY_WEBGL && !UNITY_EDITOR
using AOT;
#endif

namespace Arkadium.Interop
{
    /// <summary>
    /// Real WebGL interop provider for production builds
    /// </summary>
    public class WebGLInteropProvider : IWebGLInteropProvider
    {
#if UNITY_WEBGL && !UNITY_EDITOR
        private static readonly Dictionary<string, TaskCompletionSource<object>> _pendingTasks = new();
        private static int _taskIdCounter = 0;

        [DllImport("__Internal")]
        private static extern void _InvokeJSMethod(string methodName, string parameters, int taskId, Action<int, string> successCb, Action<int, string> errorCb);
        
        [DllImport("__Internal")]
        private static extern void _InvokeJSMethodVoid(string methodName, string parameters);
#endif

        public async Task<T> InvokeAsync<T>(string methodName, object parameters = null)
        {
#if UNITY_WEBGL && !UNITY_EDITOR
            var taskId = ++_taskIdCounter;
            var tcs = new TaskCompletionSource<object>();
            _pendingTasks[taskId.ToString()] = tcs;

            var parametersJson = parameters != null ? JsonUtility.ToJson(parameters) : "{}";
            _InvokeJSMethod(methodName, parametersJson, taskId, CompleteTask, CompleteTaskWithError);

            var result = await tcs.Task;

            if (result is T typedResult)
                return typedResult;

            if (typeof(T) == typeof(bool) && result is string boolStr)
                return (T)(object)(boolStr.ToLower() == "true");

            if (typeof(T) == typeof(int) && result is string intStr)
                return (T)(object)int.Parse(intStr);

            return (T)result;
#else
            await Task.CompletedTask; // Ensure the method is properly async
            throw new NotSupportedException("WebGLInteropProvider is only supported in WebGL builds");
#endif
        }

        public void InvokeVoid(string methodName, object parameters = null)
        {
#if UNITY_WEBGL && !UNITY_EDITOR
            var parametersJson = parameters != null ? JsonUtility.ToJson(parameters) : "{}";
            _InvokeJSMethodVoid(methodName, parametersJson);
#else
            throw new NotSupportedException("WebGLInteropProvider is only supported in WebGL builds");
#endif
        }

#if UNITY_WEBGL && !UNITY_EDITOR
        [MonoPInvokeCallback(typeof(Action<int, string>))]
        public static void CompleteTask(int taskId, string result)
        {
            if (_pendingTasks.TryGetValue(taskId.ToString(), out var tcs))
            {
                _pendingTasks.Remove(taskId.ToString());

                try
                {
                    if (result.StartsWith("{") || result.StartsWith("["))
                    {
                        tcs.SetResult(result);
                    }
                    else
                    {
                        tcs.SetResult(result);
                    }
                }
                catch
                {
                    tcs.SetResult(result);
                }
            }
        }

        [MonoPInvokeCallback(typeof(Action<int, string>))]
        public static void CompleteTaskWithError(int taskId, string error)
        {
            if (_pendingTasks.TryGetValue(taskId.ToString(), out var tcs))
            {
                _pendingTasks.Remove(taskId.ToString());
                tcs.SetException(new Exception(error));
            }
        }
#endif
    }
}