﻿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 AddText(string path, string content)
        {
            File.AppendAllText(path,content,new UTF8Encoding(false));
        }

        public static void CreateText(string path,string content="")
        {
            if (File.Exists(path) == false)
            {
                File.WriteAllText(path,content,new UTF8Encoding(false));
            }
        }

        public static bool ExistsText(string path)
        {
            return File.Exists(path);
        }

        public static void DeleteText(string path)
        {
            File.Delete(path);
        }
        
        public static string ReadText(string path)
        {
            return File.ReadAllText(path,new UTF8Encoding(false));
        }
        
        public static void WriteText(string path, string content) =>
            File.WriteAllText(path, content, new UTF8Encoding(false));
        
        public static string GetFileName(string filePath)
        {
            FileInfo f = new FileInfo(filePath);
            return f.Name.Replace(f.Extension, "");
        }
        
        public static void RemoveBoomFileOne(string path)
        {
            string content = File.ReadAllText(path);
            if (File.Exists(path)) File.Delete(path);
            var utf8WithoutBom = new System.Text.UTF8Encoding(false);

            var file = new FileStream(path, FileMode.CreateNew);
            var fileW = new StreamWriter(file, utf8WithoutBom);
            fileW.Write(content);
            fileW.Flush();
            fileW.Close();
            file.Close();
        }
        
        public static void FileChangeName(string sourceFile, string newName)
        {
            var fileInfo = new FileInfo(sourceFile);
            if (fileInfo.Exists == false) return;

            var folderName = fileInfo.DirectoryName;
            var p1 = Path.GetExtension(sourceFile);
            var p3 = $"{newName}{p1}";
            var p4 = Path.Combine(folderName, p3);

            File.Move(fileInfo.FullName, p4);
        }

        public static List<string> GetAllFilePaths(string dirPath, string mode = "*")
        {
            List<string> res = new List<string>();

            DirectoryInfo directoryInfo = new DirectoryInfo(dirPath);

            var fs = directoryInfo.GetFiles(mode);

            foreach (var f in fs)
            {
                res.Add(f.FullName);
            }

            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 GetShortForNumber(long num, string digits = "f1")
        {
            var numBit = num.ToString().Length;

            long numFloat;
            checked
            {
                numFloat = num;
            }

            if (numBit < 4) return num.ToString();

            if (numBit < 7)
            {
                numFloat /= 1000L;
                return $"{numFloat.ToString(digits)}K";
            }

            if (numBit < 10)
            {
                numFloat /= 1000000L;
                return $"{numFloat.ToString(digits)}M";
            }

            if (numBit < 13)
            {
                numFloat /= 1000000000L;
                return $"{numFloat.ToString(digits)}B";
            }

            if (numBit < 16)
            {
                numFloat /= 1000000000000L;
                return $"{numFloat.ToString(digits)}T";
            }

            if (numBit < 19)
            {
                numFloat /= 1000000000000000L;
                return $"{numFloat.ToString(digits)}aa";
            }

            if (num < long.MaxValue)
            {
                numFloat /= 1000000000000000000L;
                return $"{numFloat.ToString(digits)}bb";
            }

            //cc uu
            return "Max";
        }

        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();
        }
    }
}