using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;

namespace TFramework
{
    public static class GlobalTool
    {

        /// <summary>
        /// 当前鼠标是否停留在UGUI控件上
        /// </summary>
        /// <returns>是否</returns>
        public static bool IsPointerOverUGUI()
        {
            if (EventSystem.current)
            {
#if UNITY_ANDROID && !UNITY_EDITOR
                if (Input.touchCount > 0)
                {
                    return EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId);
                }
                else
                {
                    return false;
                }
#else
                return EventSystem.current.IsPointerOverGameObject();
#endif
            }
            else
            {
                return false;
            }
        }

        #region 反射
        private static HashSet<string> RunTimeAssemblies = new HashSet<string>()
        {
            "Assembly-CSharp","UnityEngine", "UnityEngine.CoreModule", "UnityEngine.UI", "UnityEngine.PhysicsModule","UnityEngine.EventSystems","TMPro",
            "UnityEngine.Events","TFramework.RunTime","KeMingVR"
        };

        /// <summary>
        /// 从当前程序域实例化对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="fullName"></param>
        /// <returns></returns>
        public static T CretaInstanceToCurrentDomain<T>(string fullName)where T:class
        {
            foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
                foreach (var type in assembly.GetTypes())
                    if (typeof(T).IsAssignableFrom(type))//判断type是否是其派生类
                        if (type.IsClass && type.FullName == fullName)
                            return assembly.CreateInstance(type.FullName) as T;
            return null;
        }

        /// <summary>
        /// 从当前程序域获取指定名Type
        /// </summary>
        /// <param name="typeFullName"></param>
        /// <returns></returns>
        public static Type GetTypeToCurrentDomain(string typeFullName)
        {
            Type type = null;
            foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                type = assembly.GetType(typeFullName)?? assembly.GetTypes().Find(p=>p.Name==typeFullName);

                if (type != null)
                    return type;
            }
            return type;
        }

        /// <summary>
        /// 获取运行时当前程序域所有类型
        /// </summary>
        /// <returns></returns>
        public static List<Type> GetTypesInRunTimeAssemblies()
        {
            List<Type> types = new List<Type>();
            Assembly[] assemblys = AppDomain.CurrentDomain.GetAssemblies();
            for (int i = 0; i < assemblys.Length; i++)
            {
                if (RunTimeAssemblies.Contains(assemblys[i].GetName().Name))
                {
                    types.AddRange(assemblys[i].GetTypes());
                }
            }
            return types;
        }

        /// <summary>
        /// 获取运行时当前程序域所有满足条件类型
        /// </summary>
        /// <param name="filter">筛选条件</param>
        /// <returns></returns>
        public static List<Type> GetTypesInRunTimeAssemblies(TFunc<Type, bool> filter)
        {
            List<Type> types = new List<Type>();
            Assembly[] assemblys = AppDomain.CurrentDomain.GetAssemblies();
            for (int i = 0; i < assemblys.Length; i++)
            {
                if (RunTimeAssemblies.Contains(assemblys[i].GetName().Name))
                {
                    Type[] ts = assemblys[i].GetTypes();
                    foreach (var t in ts)
                    {
                        if (filter(t))
                        {
                            types.Add(t);
                        }
                    }
                }
            }
            return types;
        }

        #endregion

        #region byte[]转换
        /// <summary>
        /// 将对象转换为byte数组
        /// </summary>
        /// <param name="obj">被转换对象</param>
        /// <returns>转换后byte数组</returns>
        public static byte[] Object2Bytes(object obj)
        {
            byte[] buff = obj != null ? new byte[Marshal.SizeOf(obj)] : new byte[0];
            if(obj!=null)
            {
                IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
                Marshal.StructureToPtr(obj, ptr, true);
            }
            return buff;
        }

        /// <summary>
        /// 将byte数组转换成对象
        /// </summary>
        /// <param name="buff">被转换byte数组</param>
        /// <param name="typ">转换成的类名</param>
        /// <returns>转换完成后的对象</returns>
        public static object Bytes2Object(byte[] buff, Type type)
        {
            IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
            return Marshal.PtrToStructure(ptr, type);
        }

        public static Texture2D Bytes2Texture2D(byte[] buff)
        {
            Texture2D texture2D = new Texture2D(512, 512);
            texture2D.LoadImage(buff);
            return texture2D;
        }

        /// <summary>
        /// 将字节数转换为最合适的存储单位表示
        /// </summary>
        /// <param name="bytes">要转换的字节数</param>
        /// <returns>带有单位的字符串表示，如"1KB"、"2.5MB"等</returns>
        public static string CalculateStorageSize(long bytes)
        {
            // 定义单位换算系数
            const long kb = 1024;
            const long mb = kb * 1024;
            const long gb = mb * 1024;

            // 根据数值大小选择合适的单位
            if (bytes >= gb)
            {
                double value = (double)bytes / gb;
                // 如果是整数则不显示小数
                return value % 1 == 0 ? $"{(long)value}G" : $"{value:F1}G";
            }
            else if (bytes >= mb)
            {
                double value = (double)bytes / mb;
                return value % 1 == 0 ? $"{(long)value}M" : $"{value:F1}M";
            }
            else if (bytes >= kb)
            {
                double value = (double)bytes / kb;
                return value % 1 == 0 ? $"{(long)value}K" : $"{value:F1}K";
            }
            else
            {
                // 小于1KB的情况直接返回字节数
                return $"{bytes}B";
            }
        }
        #endregion

        #region 截屏
        /// <summary>
        /// 截取全屏
        /// </summary>
        /// <param name="superSize">分辨率的增加倍数</param>
        /// <param name="onCaptureOverEvent">截取完成事件</param>
        public static void CaptureScreenshot(int superSize,TAction<Texture2D> onCaptureOverEvent)
        {
            Main.Instance.StartCoroutine(RecordFrame(superSize, onCaptureOverEvent));
        }

        private static IEnumerator RecordFrame(int superSize, TAction<Texture2D> onCaptureOverEvent)
        {
            yield return YieldWaitTool.YieldWaitForEndOfFrame();
            onCaptureOverEvent?.Invoke(ScreenCapture.CaptureScreenshotAsTexture(superSize));
        }

        /// <summary>
        /// 截取指定相机拍摄区域
        /// </summary>
        /// <param name="camera">截图相机</param>
        /// <param name="rect">截取区域</param>
        /// <returns></returns>
        public static Texture2D CameraCapture(Camera camera,Rect rect)
        {
            RenderTexture render = new RenderTexture((int)rect.width, (int)rect.height, -1);
            camera.targetTexture = render;
            camera.Render();
            RenderTexture currentRT = RenderTexture.active;
            RenderTexture.active = render;
            Texture2D tex = new Texture2D((int)rect.width, (int)rect.height, TextureFormat.ARGB32, false);
            tex.ReadPixels(rect, 0, 0);
            tex.Apply();

            camera.targetTexture = null;
            RenderTexture.active = currentRT; ;
            GameObject.Destroy(render);
            return tex;
        }

        /// <summary>
        /// 截取屏幕指定区域
        /// </summary>
        /// <param name="rect">截取区域</param>
        /// <param name="onCaptureOverEvent">截取完毕事件</param>
        public static void ScreenCaptureRect(Rect rect, TAction<Texture2D> onCaptureOverEvent)
        {
            Main.Instance.StartCoroutine(RecordFrame(rect, onCaptureOverEvent));
        }

        private static IEnumerator RecordFrame(Rect rect, TAction<Texture2D> onCaptureOverEvent)
        {
            yield return YieldWaitTool.YieldWaitForEndOfFrame();
            Texture2D tex = new Texture2D((int)rect.width, (int)rect.height, TextureFormat.ARGB32, false);
            tex.ReadPixels(rect, 0, 0);
            tex.Apply();
            onCaptureOverEvent?.Invoke(tex);
        }
        #endregion

        #region 贴图转换
        public static Sprite Texture2DToSprite(Texture2D texture2D) =>
            Sprite.Create(texture2D, new Rect(0, 0, texture2D.width, texture2D.height), Vector2.zero);

        public static Sprite TextureToSprite(Texture texture)
        {
            Texture2D texture2D = TextureToTexture2D(texture);

            return Texture2DToSprite(texture2D);
        }

        public static Texture2D TextureToTexture2D(Texture texture)
        {
            RenderTexture renderTexture = RenderTexture.GetTemporary(texture.width, texture.height, 32);
            Graphics.Blit(texture, renderTexture);
            Texture2D texture2D = RenderTextureToTexture2D(renderTexture);
            RenderTexture.ReleaseTemporary(renderTexture);
            return texture2D;
        }

        public static Texture2D RenderTextureToTexture2D(RenderTexture renderTexture)
        {
            RenderTexture currentRT = RenderTexture.active;
            RenderTexture.active = renderTexture;
            Rect rect = new Rect(0, 0, renderTexture.width, renderTexture.height);
            Texture2D texture2D = new Texture2D(renderTexture.width, renderTexture.height);
            texture2D.ReadPixels(rect, 0, 0);
            texture2D.Apply();
            RenderTexture.active = currentRT;
            return texture2D;
        }
        #endregion

        #region GameObject
        
        #endregion
    }
}
