﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Text.RegularExpressions;
using UnityEngine;
using Random = UnityEngine.Random;

namespace MPStudio
{
    public static class ToolCollect
    {
        public const string LowercaseLetters = "abcdefghijklmnopqrstuvwxyz";
        public const string Digits = "0123456789";

        /// <summary>
        /// 计算二次函数 f(x) = ax^2 + bx + c 在指定点 x 的导数值。
        /// </summary>
        /// <param name="a">二次项系数。</param>
        /// <param name="b">一次项系数。</param>
        /// <param name="x">计算导数的点。</param>
        /// <returns>返回在点 x 处的导数值。</returns>
        public static float CalculateDerivativeValue(float a, float b, float x)
        {
            // 导数公式为 g(x) = 2ax + b
            return 2 * a * x + b; // 导数值计算公式[^1]
        }
        
        /// <summary>
        /// 计算二次方程 ax^2 + bx + c = 0 的根。
        /// </summary>
        /// <param name="a">二次项系数。</param>
        /// <param name="b">一次项系数。</param>
        /// <param name="c">常数项。</param>
        public static void SolveQuadratic(float a, float b, float c)
        {
            if (Mathf.Abs(a) < 1e-6f)
            {
                Debug.Log("这不是一个有效的二次方程，因为 a 接近于零。");
                return;
            }

            // 计算判别式
            float discriminant = b * b - 4 * a * c;

            if (discriminant > 0)
            {
                // 两个不同的实数根
                float root1 = (-b + Mathf.Sqrt(discriminant)) / (2 * a);
                float root2 = (-b - Mathf.Sqrt(discriminant)) / (2 * a);
                Debug.Log($"方程有两个不同的实数根：x1 = {root1}, x2 = {root2}。");
            }
            else if (Mathf.Abs(discriminant) < 1e-6f)
            {
                // 一个重根
                float root = -b / (2 * a);
                Debug.Log($"方程有一个重根：x = {root}。");
            }
            else
            {
                // 两个共轭复数根
                float realPart = -b / (2 * a);
                float imaginaryPart = Mathf.Sqrt(-discriminant) / (2 * a);
                Debug.Log($"方程有两个共轭复数根：x1 = {realPart} + {imaginaryPart}i, x2 = {realPart} - {imaginaryPart}i。");
            }
        }
        
        /// <summary>
        /// 计算两条直线的交点
        /// </summary>
        /// <param name="A1">直线1的A系数</param>
        /// <param name="B1">直线1的B系数</param>
        /// <param name="C1">直线1的C系数</param>
        /// <param name="A2">直线2的A系数</param>
        /// <param name="B2">直线2的B系数</param>
        /// <param name="C2">直线2的C系数</param>
        /// <returns>交点坐标（若无交点返回null）</returns>
        public static Vector2? GetIntersection(float A1, float B1, float C1, float A2, float B2, float C2)
        {
            float denominator = A1 * B2 - A2 * B1;

            // 判断是否平行或重合
            if (Mathf.Approximately(denominator, 0f))
            {
                return null; // 无交点
            }

            float x = (B1 * C2 - B2 * C1) / denominator;
            float y = (A2 * C1 - A1 * C2) / denominator;

            return new Vector2(x, y);
        }
        
        public static float GetE()
        {
            return Mathf.Exp(1);
        }
        
        public static float GoldRatio()
        {
            return (Mathf.Sqrt(5f) - 1f) / 2f;
        }
        
        
        
        public static T DeepCopy<T>(T originObj) where T : class
        {
            using (var ms = new MemoryStream())
            {
                var fm = new BinaryFormatter();
                fm.Serialize(ms, originObj);
                ms.Seek(0, SeekOrigin.Begin);
                return (T)fm.Deserialize(ms);
            }
        }
        
        
        
        public static T GetRuleItem<T>(List<T> list, ref int index)
        {
            return list[index++ % list.Count];
        }

        public static T ListRemoveHead<T>(List<T> lis)
        {
            int headIndex = 0;
            T res = lis[headIndex];
            lis.RemoveAt(headIndex);
            return res;
        }
        
        
        
        public static void CreateFileByStream(string path, string content)
        {
            if (File.Exists(path)) File.Delete(path);

            var file = new FileStream(path, FileMode.CreateNew);
            var fileW = new StreamWriter(file, Encoding.UTF8);
            fileW.Write(content);
            fileW.Flush();
            fileW.Close();
            file.Close();
        }

        public static void CreateDir(string path)
        {
            if (Directory.Exists(path))
            {
                return;
            }

            Directory.CreateDirectory(path);
        }
        
        
        
        public static Color GetColor(int r, int g, int b, int a = 255)
        {
            return new Color(r / 255f, g / 255f, b / 255f, a / 255f);
        }

        public static Color GetColor(string c)
        {
            Color res = default;

            c = "#" + c;

            ColorUtility.TryParseHtmlString(c, out res);
            
            return res;
        }
        
        
        
        public static T RandomItem<T>(ICollection<T> ic)
        {
            return ic.ElementAt(Random.Range(0, ic.Count));
        }

        public static ICollection<T> CollectionsRandomItem<T>(ICollection<ICollection<T>> icc)
        {
            return icc.ElementAt(Random.Range(0, icc.Count));
        }
        
        public static void Shuffle<T>(List<T> poker)
        {
            for (var i = poker.Count - 1; i >= 0; i--)
            {
                var randomIndex = Random.Range(0, i + 1);
                var temp = poker[randomIndex];
                poker[randomIndex] = poker[i];
                poker[i] = temp;
            }
        }
        
        public static bool CanBirthPrecision1000(float birthProbability)
        {
            var random = Random.Range(1, 1001);
            var birthValue = (int)(birthProbability * 1000);
            return random <= birthValue;
        }

        public static float GetRandomPlusAndMinus(float val)
        {
            return Random.Range(-val, val);
        }
        
        
        
        public static T GetField<T>(object ins, string name)
        {
            var temp = ins.GetType().GetField(name).GetValue(ins);

            return (T)temp;
        }
        
        
        
        public static string DollarFormat(double num, bool isIgnorePoint = true)
        {
            var str = string.Format("{0:N}", num);
            if (isIgnorePoint)
                return str.Replace(".00", "");
            return str;
        }

        public static int GetPureNumber(string str)
        {
            var newStr = Regex.Replace(str, "[^0-9]*", "");
            if (newStr == "") return 0;
            return int.Parse(newStr);
        }

        public static string StrRepeat(string demo, int repeatCount)
        {
            StringBuilder sb = new StringBuilder();
            int step = 0;
            while (step < repeatCount)
            {
                sb.Append(demo);
                step += 1;
            }

            return sb.ToString();
        }

        public static string GetRatio(float val, string format = "f1")
        {
            var tempVal = val;
            tempVal *= 100;
            return tempVal.ToString(format) + "%";
        }
        
        
        
        public static T GetEnumByInt<T>(int val) where T : Enum
        {
            return (T)Enum.Parse(typeof(T), val.ToString());
        }

        public static List<T> GetEnums<T>() where T : Enum
        {
            return Enum.GetValues(typeof(T)).Cast<T>().ToList();
        }
    }
}