using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;

namespace TFramework
{
    /// <summary>
    /// 函数扩展类
    /// </summary>
    public static class FunctionExtend
    {
        #region 对象
        /// <summary>
        /// 设置游戏对象激活状态
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="game"></param>
        /// <param name="value"></param>
        public static GameObject SetActive<T>(this T game, bool value) where T : Component
        {
            game.gameObject.SetActive(value);
            return game.gameObject;
        }

        /// <summary>
        /// 给物体添加交互事件 点击 拖拽...
        /// </summary>
        /// <param name="obj">物体对象</param>
        /// <param name="ev">交互类型</param>
        /// <param name="action">事件</param>
        public static void AddTriggerListener<T>(this T obj, EventTriggerType ev, UnityAction<BaseEventData> action) where T : Component
        {
            EventTrigger trigger = obj.GetComponent<EventTrigger>() ?? obj.gameObject.AddComponent<EventTrigger>();

            trigger.triggers = trigger.triggers ?? new List<EventTrigger.Entry>();

            foreach (var item in trigger.triggers)
            {
                if (item.eventID == ev)
                {
                    item.callback.AddListener(action);
                    return;
                }
            }

            EventTrigger.Entry entry = new EventTrigger.Entry();

            entry.eventID = ev;
            entry.callback.AddListener(action);
            trigger.triggers.Add(entry);
        }

        /// <summary>
        /// 移除物体交互事件
        /// </summary>
        /// <param name="obj">物体对象</param>
        /// <param name="ev">交互类型</param>
        /// <param name="action">事件</param>
        public static void RemoveTriggerListener<T>(this T obj, EventTriggerType ev, UnityAction<BaseEventData> action) where T : Component
        {
            EventTrigger trigger = obj.GetComponent<EventTrigger>();
            if (trigger == null)
                return;

            if (trigger.triggers == null || trigger.triggers.Count == 0)
                return;
            foreach (var item in trigger.triggers)
            {
                if (item.eventID == ev)
                    item.callback.RemoveListener(action);
            }
        }

        /// <summary>
        /// 克隆
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="clone"></param>
        /// <param name="parent"></param>
        /// <param name="isUI"></param>
        /// <returns></returns>
        public static T Clone<T>(this T clone, Transform parent=null, bool isUI = false) where T : UnityEngine.Object
        {
            UnityEngine.Object obj;
            if (parent != null)
                obj = GameObject.Instantiate(clone, parent);
            else
                obj = GameObject.Instantiate(clone);
            if (isUI)
            {
                UIBehaviour[] uis = (obj as Component).GetComponentsInChildren<UIBehaviour>(true);
                for (int i = 0; i < uis.Length; i++)
                    uis[i].ResetID();
            }
            return obj as T;
        }

        /// <summary>
        /// 根据名字查找对应类型子游戏对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="game"></param>
        /// <param name="n"></param>
        /// <returns></returns>
        public static T GetChildComponent<T>(this GameObject game, string n) where T : UnityEngine.Object
        {
            Transform t = game.transform.Find(n);
            return t != null ? t.GetComponent<T>() : null;
        }

        /// <summary>
        /// 根据名字查找对应类型子游戏对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="game"></param>
        /// <param name="n"></param>
        /// <returns></returns>
        public static T GetChildComponent<T>(this Component game, string n) where T : UnityEngine.Object
        {
            Transform t = game.transform.Find(n);
            return t != null ? t.GetComponent<T>() : null;
        }

        /// <summary>
        /// 查找第一个名字含有指定字符的子物体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="game"></param>
        /// <param name="n"></param>
        /// <returns></returns>
        public static T GetContainStrChildComponent<T>(this GameObject game, string n) where T : UnityEngine.Object
        {
            return game.GetComponentsInChildren<T>(true).First(p => p.name.Contains(n));
        }

        #endregion

        #region 反射
        /// <summary>
        /// 从当前类型中获取所有字段
        /// </summary>
        /// <param name="type">类型</param>
        /// <param name="filter">字段筛选器</param>
        /// <returns>所有字段集合</returns>
        public static List<FieldInfo> GetFields(this Type type, TFunc<FieldInfo, bool> filter)
        {
            List<FieldInfo> fields = new List<FieldInfo>();
            FieldInfo[] infos = type.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
            for (int i = 0; i < infos.Length; i++)
            {
                if (filter(infos[i]))
                {
                    fields.Add(infos[i]);
                }
            }
            return fields;
        }
        /// <summary>
        /// 从当前类型中获取所有属性
        /// </summary>
        /// <param name="type">类型</param>
        /// <param name="filter">属性筛选器</param>
        /// <returns>所有属性集合</returns>
        public static List<PropertyInfo> GetProperties(this Type type, TFunc<PropertyInfo, bool> filter)
        {
            List<PropertyInfo> properties = new List<PropertyInfo>();
            PropertyInfo[] infos = type.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
            for (int i = 0; i < infos.Length; i++)
            {
                if (filter(infos[i]))
                {
                    properties.Add(infos[i]);
                }
            }
            return properties;
        }
        /// <summary>
        /// 从当前类型中获取所有方法
        /// </summary>
        /// <param name="type">类型</param>
        /// <param name="filter">方法筛选器</param>
        /// <returns>所有方法集合</returns>
        public static List<MethodInfo> GetMethods(this Type type, TFunc<MethodInfo, bool> filter)
        {
            List<MethodInfo> methods = new List<MethodInfo>();
            MethodInfo[] infos = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
            for (int i = 0; i < infos.Length; i++)
            {
                if (filter(infos[i]))
                {
                    methods.Add(infos[i]);
                }
            }
            return methods;
        }

        /// <summary>
        /// 从当前类型中获取所有成员
        /// </summary>
        /// <param name="type"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public static List<MemberInfo> GetMembers(this Type type,TFunc<MemberInfo,bool> filter)
        {
            List<MemberInfo> memberInfos = new List<MemberInfo>();
            MemberInfo[] infos = type.GetMembers(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
            for (int i = 0; i < infos.Length; i++)
            {
                if (filter(infos[i]))
                {
                    memberInfos.Add(infos[i]);
                }
            }
            return memberInfos;
        }
        #endregion

        #region 集合
        public static bool Contains<T>(this T[] array, T item) => Array.Exists(array, p => p.Equals(item));

        public static T Find<T>(this T[] array, Predicate<T> match) => Array.Find(array, match);

        /// <summary>
        /// 根据Key获取Value
        /// </summary>
        /// <typeparam name="Tkey"></typeparam>
        /// <typeparam name="Tvalue"></typeparam>
        /// <param name="dict">获取值的字典</param>
        /// <param name="key">键值</param>
        /// <returns></returns>
        public static Tvalue TryGet<Tkey, Tvalue>(this Dictionary<Tkey, Tvalue> dict, Tkey key)
        {
            Tvalue value;
            dict.TryGetValue(key, out value);
            return value;
        }

        /// <summary>
        /// 打乱列表顺序
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        public static void OutOfOrder<T>(this List<T> list)
        {
            T t = default;
            for (int i = 0; i < list.Count; i++)
            {
                int index = UnityEngine.Random.Range(0, list.Count);
                t = list[index];
                list[index] = list[i];
                list[i] = t;
            }
        }

        /// <summary>
        /// 替换列表元素的位置
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="list">列表</param>
        /// <param name="index1">需替换位置元素下标</param>
        /// <param name="index2">需替换位置元素下标</param>
        public static void Swap<T>(this List<T> list, int index1, int index2)
        {
            if (index1 >= list.Count || index2 >= list.Count || index1 < 0 || index2 < 0) return;
            T temp1 = list[index1];
            list[index1] = list[index2];
            list[index2] = temp1;
        }
        #endregion

        #region 字符串
        public static string StrUnescape(this string str) => Regex.Unescape(str);

        private static string pattern = @"(\d*\.|[0-9]+)[0-9]+";

        /// <summary>
        /// 获取字符串中所有数值
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static List<float> GetStrAllNumValue(this string str)
        {
            List<float> values = new List<float>();
            Regex regex = new Regex(pattern);
            MatchCollection matchs = regex.Matches(str);
            foreach (Match item in matchs)
            {
                if (float.TryParse(item.Groups[0].Value, out float v))
                    values.Add(v);
            }
            return values;
        }

        /// <summary>
        /// Json字符串转object
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jsonStr"></param>
        /// <returns></returns>
        public static T JsonStrToObject<T>(this string jsonStr)
        {
            return JsonConvert.DeserializeObject<T>(jsonStr);
        }

        /// <summary>
        /// 泛型转Json字符串
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string ObjectToJsonStr<T>(this T obj)
        {
            return Regex.Unescape(JsonConvert.SerializeObject(obj));
        }
        #endregion

        #region 数学
        /// <summary>
        /// 除法运算（避免Nan）
        /// </summary>
        /// <param name="dividend">被除数</param>
        /// <param name="divisor">除数</param>
        /// <returns>商</returns>
        public static float Divide(this float dividend, float divisor)
        {
            if (divisor == 0)
                return dividend;
            else
                return dividend / divisor;
        }
        #endregion

        public static Vector2 Clamp(this Vector2 v2, float min, float max)
        {
            Vector2 vect2 = Vector2.zero;
            vect2.x = Mathf.Clamp(v2.x, min, max);
            vect2.y = Mathf.Clamp(v2.y, min, max);
            return vect2;
        }

        #region 音频
        /// <summary>
        ///AudioClip转wave格式文件byte数组
        /// </summary>
        /// <param name="clip"></param>
        /// <returns></returns>
        public static byte[] ClipToBytes(this AudioClip clip)
        {
            byte[] buffer = GetRealAudio(ref clip);
            return GetHeaderBytes(buffer, clip).Concat(buffer).ToArray();
        }

        public static AudioClip BytesToAudioClip(this byte[] wavFileData)
        {
            int channels = BitConverter.ToInt16(wavFileData, 22);
            int sampleRate = BitConverter.ToInt32(wavFileData, 24);

            byte[] data = new byte[wavFileData.Length - 44];
            Array.Copy(wavFileData, 44, data, 0, wavFileData.Length - 44);

            float[] _clipData = BytesToFloat(data);
            AudioClip clip = AudioClip.Create("audioClip", _clipData.Length, channels, sampleRate, false);
            clip.SetData(_clipData, 0);
            return clip;
        }

        /// <summary>
        /// 获取录音头部 wave格式
        /// </summary>
        /// <param name="data"></param>
        /// <param name="clip"></param>
        /// <returns></returns>
        private static byte[] GetHeaderBytes(byte[] data, AudioClip clip)
        {
            byte[] buffer = new byte[44];
            int hz = clip.frequency;
            int channels = clip.channels;
            int samples = clip.samples;

            int index = 0;

            Byte[] riff = Encoding.UTF8.GetBytes("RIFF");
            for (int i = 0; i < 4; i++)
            {
                buffer[index] = riff[i];
                index += 1;
            }

            Byte[] chunkSize = BitConverter.GetBytes(data.Length - 8);
            for (int i = 0; i < 4; i++)
            {
                buffer[index] = chunkSize[i];
                index += 1;
            }

            Byte[] wave = Encoding.UTF8.GetBytes("WAVE");
            for (int i = 0; i < 4; i++)
            {
                buffer[index] = wave[i];
                index += 1;
            }

            Byte[] fmt = Encoding.UTF8.GetBytes("fmt ");
            for (int i = 0; i < 4; i++)
            {
                buffer[index] = fmt[i];
                index += 1;
            }

            Byte[] subChunk1 = BitConverter.GetBytes(16);
            for (int i = 0; i < 4; i++)
            {
                buffer[index] = subChunk1[i];
                index += 1;
            }

            UInt16 one = 1;
            Byte[] audioFormat = BitConverter.GetBytes(one);
            for (int i = 0; i < 2; i++)
            {
                buffer[index] = audioFormat[i];
                index += 1;
            }

            Byte[] numChannels = BitConverter.GetBytes(channels);
            for (int i = 0; i < 2; i++)
            {
                buffer[index] = numChannels[i];
                index += 1;
            }

            Byte[] sampleRate = BitConverter.GetBytes(hz);
            for (int i = 0; i < 4; i++)
            {
                buffer[index] = sampleRate[i];
                index += 1;
            }

            Byte[] byteRate = BitConverter.GetBytes(hz * channels * 2);
            for (int i = 0; i < 4; i++)
            {
                buffer[index] = byteRate[i];
                index += 1;
            }

            UInt16 blockAlign = (ushort)(channels * 2);
            byte[] blockAlignBytes = BitConverter.GetBytes(blockAlign);
            for (int i = 0; i < 2; i++)
            {
                buffer[index] = blockAlignBytes[i];
                index += 1;
            }

            UInt16 bps = 16;
            Byte[] bitsPerSample = BitConverter.GetBytes(bps);
            for (int i = 0; i < 2; i++)
            {
                buffer[index] = bitsPerSample[i];
                index += 1;
            }

            Byte[] datastring = System.Text.Encoding.UTF8.GetBytes("data");
            for (int i = 0; i < 4; i++)
            {
                buffer[index] = datastring[i];
                index += 1;
            }

            Byte[] subChunk2 = BitConverter.GetBytes(samples * channels * 2);
            for (int i = 0; i < 4; i++)
            {
                buffer[index] = subChunk2[i];
                index += 1;
            }

            return buffer;
        }

        /// <summary>
        /// 获取真正大小的录音
        /// </summary>
        /// <param name="recordedClip"></param>
        /// <returns></returns>
        private static byte[] GetRealAudio(ref AudioClip recordedClip)
        {
            int position = Microphone.GetPosition(null);
            if (position <= 0 || position > recordedClip.samples)
            {
                position = recordedClip.samples;
            }
            float[] soundata = new float[position * recordedClip.channels];
            recordedClip.GetData(soundata, 0);
            recordedClip = AudioClip.Create(recordedClip.name, position,
            recordedClip.channels, recordedClip.frequency, false);
            recordedClip.SetData(soundata, 0);
            int rescaleFactor = 32767;
            byte[] outData = new byte[soundata.Length * 2];
            for (int i = 0; i < soundata.Length; i++)
            {
                short temshort = (short)(soundata[i] * rescaleFactor);
                byte[] temdata = BitConverter.GetBytes(temshort);
                outData[i * 2] = temdata[0];
                outData[i * 2 + 1] = temdata[1];
            }
            return outData;
        }

        private static float[] BytesToFloat(byte[] data)
        {
            float[] sounddata = new float[data.Length / 2];
            for (int i = 0; i < sounddata.Length; i++)
            {
                sounddata[i] = ByteToFloat(data[i * 2], data[i * 2 + 1]);
            }
            return sounddata;
        }

        private static float ByteToFloat(byte firstByte, byte secondByte)
        {
            short s;
            if (BitConverter.IsLittleEndian)
                s = (short)((secondByte << 8) | firstByte);
            else
                s = (short)((firstByte << 8) | secondByte);
            return s / 32768.0F;
        }
        #endregion
    }
}
