using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace tysdk
{
    /// <summary>
    /// 线程安全的异步Callback管理器
    /// 解决原有callback系统的线程安全、内存泄漏和超时问题
    /// </summary>
    public class TYSDKCallbackManager : IDisposable
    {
        private static readonly Lazy<TYSDKCallbackManager> _instance =
            new Lazy<TYSDKCallbackManager>(() => new TYSDKCallbackManager());

        public static TYSDKCallbackManager Instance => _instance.Value;

        private readonly ConcurrentDictionary<string, CallbackEntry> _callbacks = new();
        private readonly object _lock = new();
        private bool _disposed = false;

        private TYSDKCallbackManager() { }

        /// <summary>
        /// 注册一个callback并返回Task
        /// </summary>
        /// <typeparam name="T">Callback数据类型</typeparam>
        /// <param name="callbackType">Callback类型标识</param>
        /// <param name="timeout">超时时间，默认15 sec</param>
        /// <returns>Task用于等待callback结果</returns>
        public Task<T> RegisterCallback<T>(TimeSpan? timeout = null) where T : class
        {
            if (_disposed)
                throw new ObjectDisposedException(nameof(TYSDKCallbackManager));

            var callbackId = typeof(T).Name;

            if (_callbacks.TryGetValue(callbackId, out var entry))
            {
                UnityEngine.Debug.Log($"[TYSDKCallbackManager] Registered callback exists {callbackId}");
                return entry.Task as Task<T>;
            }

            var tcs = new TaskCompletionSource<T>(TaskCreationOptions.RunContinuationsAsynchronously);
            var actualTimeout = timeout ?? TimeSpan.FromSeconds(15);
            var cts = new CancellationTokenSource(actualTimeout);

            entry = new CallbackEntry<T>
            {
                TaskCompletionSource = tcs,
                CancellationTokenSource = cts,
            };

            // 注册到字典
            _callbacks[callbackId] = entry;

            // 设置超时取消
            cts.Token.Register(() =>
            {
                if (tcs.TrySetCanceled())
                {
                    UnityEngine.Debug.LogWarning($"[TYSDKCallbackManager] Callback {callbackId} timed out after {actualTimeout.TotalSeconds}s");
                }
                _callbacks.TryRemove(callbackId, out _);
            });

            UnityEngine.Debug.Log($"[TYSDKCallbackManager] Registered callback {callbackId}");
            return tcs.Task;
        }

        /// <summary>
        /// 触发callback
        /// </summary>
        /// <typeparam name="T">Callback数据类型</typeparam>
        /// <param name="callbackType">Callback类型标识</param>
        /// <param name="callbackData">Callback数据</param>
        /// <returns>是否成功触发callback</returns>
        public bool TryTriggerCallback<T>(T callbackData) where T : class
        {
            if (_disposed || callbackData == null)
                return false;

            var key = typeof(T).Name;
            if (!_callbacks.TryGetValue(key, out var entry))
            {
                UnityEngine.Debug.LogWarning($"[TYSDKCallbackManager] No pending callback found for type: {key}");
                return false;
            }

            if (entry == null)
            {
                _callbacks.TryRemove(key, out _);
                return false;
            }

            if (entry.Task.IsCompleted)
            {
                entry.CancellationTokenSource?.Cancel();
                _callbacks.TryRemove(key, out _);
                return false;
            }

            var actualEntry = entry as CallbackEntry<T>;

            if (actualEntry == null)
            {
                UnityEngine.Debug.LogError($"[TYSDKCallbackManager] Callback type mismatch: Expected {typeof(T).Name}, but got {entry.GetType().Name}");
                entry.CancellationTokenSource?.Cancel();
                return false;
            }

            try
            {
                // 尝试设置结果
                if (actualEntry.TaskCompletionSource.TrySetResult(callbackData))
                {
                    actualEntry.CancellationTokenSource?.Cancel();
                    UnityEngine.Debug.Log($"[TYSDKCallbackManager] Successfully triggered callback {key}");
                    return true;
                }
            }
            catch (Exception ex)
            {
                UnityEngine.Debug.LogError($"[TYSDKCallbackManager] Error triggering callback {key}: {ex.Message}\n{ex.StackTrace}");
                actualEntry.TaskCompletionSource.TrySetException(ex);
                actualEntry.CancellationTokenSource?.Cancel();
                return false;
            }

            return false;
        }

        /// <summary>
        /// 取消指定类型的所有callback
        /// </summary>
        /// <param name="callbackType">Callback类型</param>
        /// <param name="reason">取消原因</param>
        public void CancelCallbacks<T>()
        {
            var key = typeof(T).Name;

            if (!_callbacks.TryGetValue(key, out var entryToRemove))
            {
                UnityEngine.Debug.LogWarning($"[TYSDKCallbackManager] No pending callback found for type: {key}");
                return;
            }

            entryToRemove.Cancel();
        }

        public int GetCallbackNum()
        {
          return _callbacks?.Count ?? 0;
        }

        public void Dispose()
        {
            if (_disposed) return;

            lock (_lock)
            {
                if (_disposed) return;
                _disposed = true;

                // 取消所有pending callbacks
                foreach (var entry in _callbacks.Values)
                {
                    try
                    {
                        if (!entry.Task.IsCompleted)
                        {
                            entry.Cancel();
                        }
                    }
                    catch
                    {
                        // 忽略取消时的异常
                    }

                    entry.CancellationTokenSource?.Dispose();
                }

                _callbacks.Clear();
                UnityEngine.Debug.Log("[TYSDKCallbackManager] Disposed");
            }
        }

        private abstract class CallbackEntry
        {
            public CancellationTokenSource CancellationTokenSource { get; set; } = null!;
            public abstract Task Task { get; }
            public abstract void Cancel();
        }

        private class CallbackEntry<T> : CallbackEntry where T : class
        {
            public TaskCompletionSource<T> TaskCompletionSource { get; set; } = null!;
            public override Task Task => TaskCompletionSource.Task;

            public override void Cancel()
            {
                TaskCompletionSource.TrySetCanceled();
                CancellationTokenSource?.Cancel();
            }
        }
    }
}
