// Copyright (c) 2026 EzAdmin. All rights reserved.
// Licensed under the EzAdmin Client License. See LICENSE-CLIENT.txt.

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

namespace EzAdmin.Client
{

    public static class EzAdminProfiles
    {

        public static float CacheSeconds = 300f;

        private struct Cached
        {
            public EzAdminProfile Profile;
            public float At;
        }

        private static readonly Dictionary<string, Cached> Profiles = new Dictionary<string, Cached>();
        private static readonly Dictionary<string, Texture2D> Avatars = new Dictionary<string, Texture2D>();
        private static readonly Dictionary<string, List<Action<Texture2D>>> Loading =
            new Dictionary<string, List<Action<Texture2D>>>();

        public static void Get(string playFabId, Action<EzAdminProfile> onComplete)
        {
            Get(new[] { playFabId }, all => onComplete?.Invoke(all[playFabId]));
        }

        public static void Get(IList<string> playFabIds, Action<Dictionary<string, EzAdminProfile>> onComplete)
        {
            var result = new Dictionary<string, EzAdminProfile>();
            var missing = new List<string>();
            float now = Time.realtimeSinceStartup;
            foreach (var id in playFabIds)
            {
                if (string.IsNullOrEmpty(id) || result.ContainsKey(id)) continue;
                Cached hit;
                if (Profiles.TryGetValue(id, out hit) && now - hit.At < CacheSeconds)
                {
                    result[id] = hit.Profile;
                }
                else
                {
                    missing.Add(id);
                }
            }
            var client = EzAdminClient.Instance;
            if (missing.Count == 0 || client == null)
            {
                foreach (var id in missing) result[id] = EzAdminProfile.Unavailable;
                onComplete?.Invoke(result);
                return;
            }
            client.ViewProfiles(missing, fetched =>
            {
                float at = Time.realtimeSinceStartup;
                foreach (var pair in fetched)
                {
                    result[pair.Key] = pair.Value;
                    if (!pair.Value.Unreachable)
                    {
                        Profiles[pair.Key] = new Cached { Profile = pair.Value, At = at };
                    }
                }
                onComplete?.Invoke(result);
            });
        }

        public static void LoadAvatar(string avatarUrl, Action<Texture2D> onLoaded, int size = 128)
        {
            if (string.IsNullOrEmpty(avatarUrl) || onLoaded == null)
            {
                onLoaded?.Invoke(null);
                return;
            }
            string url = WithSize(avatarUrl, size);
            Texture2D texture;
            if (Avatars.TryGetValue(url, out texture) && texture != null)
            {
                onLoaded(texture);
                return;
            }
            List<Action<Texture2D>> waiting;
            if (Loading.TryGetValue(url, out waiting))
            {
                waiting.Add(onLoaded);
                return;
            }
            var client = EzAdminClient.Instance;
            if (client == null)
            {
                onLoaded(null);
                return;
            }
            Loading[url] = new List<Action<Texture2D>> { onLoaded };
            client.StartCoroutine(Download(url));
        }

        public static void ClearCache()
        {
            Profiles.Clear();
        }

        private static IEnumerator Download(string url)
        {
            Texture2D texture = null;
            using (var request = UnityWebRequestTexture.GetTexture(url))
            {
                request.timeout = 20;
                yield return request.SendWebRequest();
                if (request.result == UnityWebRequest.Result.Success)
                {
                    texture = DownloadHandlerTexture.GetContent(request);
                    texture.name = "Discord avatar";
                    Avatars[url] = texture;
                }
            }
            List<Action<Texture2D>> waiting;
            if (Loading.TryGetValue(url, out waiting))
            {
                Loading.Remove(url);
                foreach (var callback in waiting) callback?.Invoke(texture);
            }
        }

        private static string WithSize(string url, int size)
        {

            int clamped = Mathf.ClosestPowerOfTwo(Mathf.Clamp(size, 16, 1024));
            int query = url.IndexOf('?');
            string bare = query >= 0 ? url.Substring(0, query) : url;
            return bare + "?size=" + clamped;
        }

        [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
        private static void ResetOnPlay()
        {
            Profiles.Clear();
            Avatars.Clear();
            Loading.Clear();
        }
    }
}
