using Microsoft.AspNetCore.Cryptography.KeyDerivation;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;

namespace TEAMModelOS.SDK.Extension
{
    public class Utils
    {
        private static RNGCryptoServiceProvider _random = new RNGCryptoServiceProvider();

        public static string HashedPassword(string password, string salt)
        {
            byte[] hashBytes = KeyDerivation.Pbkdf2(
                password: password,
                salt: Encoding.UTF8.GetBytes(salt), //SHA1鹽(8-20字節)，SHA256(32字節)
                prf: KeyDerivationPrf.HMACSHA1,
                iterationCount: 10000, //hash次數，越多次代表破解難度變高，但效能會差點
                numBytesRequested: 256 / 8 //指定得出結果長度
            );

            string hashText = BitConverter.ToString(hashBytes).Replace("-", string.Empty);
            return hashText;
        }

        /// <summary>
        /// 建立真隨機字串(CSPRNG)，適用密碼、鹽
        /// </summary>
        /// <param name="stringLength">長度</param>
        /// <param name="key">要限制的字元串(長度需大於等於8)，如果為null或者小於8，預設為"abcdefghijklmnopqrstuvwxyz1234567890"</param>
        /// <returns></returns>
        public static string CreatSaltString(int stringLength, string key = null)
        {
            ReadOnlySpan<char> span;
            if (key == null || key.Length < 8)
                span = "abcdefghijklmnopqrstuvwxyz1234567890";
            else
                span = key.AsSpan();

            int length = span.Length;
            StringBuilder randomString = new StringBuilder(length);
            for (int i = 0; i < stringLength; ++i)
            {
                randomString.Append(span[SetRandomSeeds(length)]);
            }
            return randomString.ToString();
        }

        /// <summary>
        /// 建立真隨機整數數字(CSPRNG)，適用亂數、隨機編號
        /// </summary>
        /// <param name="max">最大值</param>
        public static int CreatSaltInt(int max)
        {
            var bytes = new byte[4];
            _random.GetBytes(bytes);
            int value = BitConverter.ToInt32(bytes, 0);
            value = value % (max + 1);
            if (value < 0) value = -value;
            return value;
        }

        /// <summary>
        /// 建立真隨機整數數字(CSPRNG)，適用亂數、隨機編號
        /// </summary>
        /// <param name="min">最小值</param>
        /// <param name="max">最大值</param>
        public static int CreatSaltInt(int min, int max)
        {
            int value = CreatSaltInt(max - min) + min;
            return value;
        }

        /// <summary>
        /// 剖析連接字串
        /// </summary>
        /// <param name="connectionString"></param>
        /// <returns></returns>
        public static Dictionary<string, string> ParseConnectionString(string connectionString)
        {
            var d = new Dictionary<string, string>();
            foreach (var item in connectionString.Split(';', StringSplitOptions.RemoveEmptyEntries))
            {
                var a = item.IndexOf('=');
                d.Add(item.Substring(0, a), item.Substring(a + 1));
            }
            return d;
        }

        #region 圖片處理
        /// <summary>
        /// 判斷圖片格式
        /// </summary>
        /// <param name="stream">傳入Stream，注意請自行釋放</param>
        /// <returns></returns>
        public static (bool, string, int) ImageValidateByStream(Stream stream)
        {
            int length = 1024;
            byte[] bytes = new byte[1024];
            BinaryReader br = new BinaryReader(stream);
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < length; i++)
            {
                byte tempByte = br.ReadByte();
                bytes[i] = tempByte;
                stringBuilder.Append(Convert.ToString(tempByte, 16));
                stringBuilder.Append(",");
            }
            stream.Position = 0; //指針回歸為0

            string fileheader = stringBuilder.ToString().ToUpper();
            if (string.IsNullOrWhiteSpace(fileheader))
                return (false, "", 0);

            if (fileheader.StartsWith("FF,D8,") || fileheader.StartsWith("42,4D,"))
            {
                int i = 2;
                int depth;
                while (true)
                {
                    int marker = (bytes[i] & 0xff) << 8 | (bytes[i + 1] & 0xff);
                    int size = (bytes[i + 2] & 0xff) << 8 | (bytes[i + 3] & 0xff);
                    if (marker >= 0xffc0 && marker <= 0xffcf && marker != 0xffc4 && marker != 0xffc8)
                    {
                        depth = (bytes[i + 4] & 0xff) * (bytes[i + 9] & 0xff);
                        break;
                    }
                    else i += size + 2;
                }
                return (true, "jpg", depth);
            }
            if (fileheader.StartsWith("89,50,4E,47,D,A,1A,A,"))
            {
                int depth = bytes[24] & 0xff;
                if ((bytes[25] & 0xff) == 2) depth *= 3;
                else if ((bytes[25] & 0xff) == 6) depth *= 4;

                return (true, "png", depth);
            }
            
            if (fileheader.StartsWith("47,49,46,38,39,61,") || fileheader.StartsWith("47,49,46,38,37,61,"))
                return (true, "gif", 0);

            if (fileheader.StartsWith("1,0,0,0,"))
                return (true, "emf", 0);

            if (fileheader.StartsWith("1,0,9,0,0,3"))
                return (true, "wmf", 0);
            //if (fileheader.StartsWith("4D,4D") || fileheader.StartsWith("49,49") || fileheader.StartsWith("46,4F,52,4D"))
            //    return (true, "tif");
            return (false, "", 0);

        }

        /// <summary>
        /// 轉換EMF為PNG格式
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static string ConvertEMFtoPNG(Stream stream) 
        {
            using var image = Image.FromStream(stream);

            //GDI+報錯，Azure Web App沙箱不支持GDI+部分權限
            //using var nbase64ms = new MemoryStream();
            //image.Save(nbase64ms, ImageFormat.Png); //保存為PNG格式
            //byte[] data = nbase64ms.ToArray();
            //string base64 = Convert.ToBase64String(data);
            //return base64;

            //Azure Web App沙箱不支持GDI+渲染部分EMF指令，可以出圖但會是空白
            var pngimage = new Bitmap(image.Width, image.Height);
            using (var graphics = Graphics.FromImage(pngimage))
            {
                graphics.CompositingQuality = CompositingQuality.HighSpeed;
                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                graphics.CompositingMode = CompositingMode.SourceCopy;
                graphics.DrawImage(image, 0, 0, image.Width, image.Height);
                using var nbase64ms = new MemoryStream();
                pngimage.Save(nbase64ms, ImageFormat.Png); //保存為PNG格式
                byte[] data = nbase64ms.ToArray();
                string base64 = Convert.ToBase64String(data);
                return base64;
            }
        }
        #endregion




        #region private
        private static int SetRandomSeeds(int length)
        {
            decimal maxValue = (decimal)long.MaxValue;
            byte[] array = new byte[8];
            _random.GetBytes(array);
            return (int)(Math.Abs(BitConverter.ToInt64(array, 0)) / maxValue * length);
        }

        #endregion


    }
}
