using System;
using System.Collections.Generic;
using Top.Api.Util;
using System.Text;


namespace Top.Api.Security
{

    public class SecurityBiz : SecurityConstants
    {
        private static IDictionary<string, Nullable<char>> SEPARATOR_CHAR_MAP = InitSeparatorCharMap();
        private static IDictionary<string, string> SEPARATOR_MAP = InitSeparatorMap();

        private static IDictionary<string, Nullable<char>> InitSeparatorCharMap()
        {
            IDictionary<string, Nullable<char>> map = new Dictionary<string, Nullable<char>>();
            map.Add(NICK, SIMPLE_CHAR);
            map.Add(RECEIVER_NAME, SIMPLE_CHAR);
            map.Add(NORMAL, NORMAL_SEPARATOR_CHAR);
            map.Add(PHONE, PHONE_SEPARATOR_CHAR);
            map.Add(SIMPLE, SIMPLE_CHAR);
            map.Add(SEARCH, SIMPLE_CHAR);
            return map;
        }


        private static IDictionary<string, string> InitSeparatorMap()
        {
            IDictionary<string, string> map = new Dictionary<string, string>();
            map.Add(NICK, SIMPLE_SEPARATOR);
            map.Add(RECEIVER_NAME, SIMPLE_SEPARATOR);
            map.Add(NORMAL, NORMAL_SEPARATOR);
            map.Add(PHONE, PHONE_SEPARATOR);
            map.Add(SIMPLE, SIMPLE_SEPARATOR);
            map.Add(SEARCH, SIMPLE_SEPARATOR);
            return map;
        }

        public static IDictionary<string, Nullable<char>> GetSeparatorCharMap()
        {
            return SEPARATOR_CHAR_MAP;
        }

        public static IDictionary<string, string> GetSeparatorMap()
        {
            return SEPARATOR_MAP;
        }

        /// <summary>
        /// 判断是否密文数据
        /// </summary>
        /// <param name="data"></param>
        /// <param name="type">加密字段类型(例如：simple\phone)</param>
        /// <returns></returns>
        public static bool IsEncryptData(string data, string type)
        {
            if (string.IsNullOrEmpty(data) || data.Length < 4)
            {
                return false;
            }

            Nullable<char> charValue = null;
            SEPARATOR_CHAR_MAP.TryGetValue(type, out charValue);
            if (charValue == null)
            {
                throw new SecretException("type error");
            }
            char separatorChar = charValue.Value;
            if (!(data[0] == charValue && data[data.Length - 1] == charValue))
            {
                return false;
            }

            if (separatorChar == PHONE_SEPARATOR_CHAR)
            {
                // 拆分元素
                string[] dataArray = StringUtil.Split(data, separatorChar);
                if (dataArray.Length != 3)
                {
                    return false;
                }
                if (data[data.Length - 2] == separatorChar)
                {
                    return CheckEncryptData(dataArray);
                }
                else
                {

                    string version = dataArray[dataArray.Length - 1];
                    if (StringUtil.IsNumeric(version))
                    {
                        bool isBase64Value = SecurityUtil.IsBase64Value(dataArray[dataArray.Length - 2]);
                        if (isBase64Value)
                        {
                            return true;
                        }
                        return false;
                    }
                }
            }
            else
            {
                // 拆分元素
                string[] dataArray = StringUtil.Split(data, separatorChar);
                if (data[data.Length - 2] == separatorChar)
                {
                    if (dataArray.Length != 3)
                    {
                        return false;
                    }
                    return CheckEncryptData(dataArray);
                }
                else
                {
                    if (dataArray.Length != 2)
                    {
                        return false;
                    }
                    return CheckEncryptData(dataArray);
                }
            }

            return false;
        }

       /// <summary>
        /// 判断是否密文数据
       /// </summary>
       /// <param name="dataArray"></param>
       /// <returns></returns>
        private static bool CheckEncryptData(string[] dataArray)
        {
            string version = dataArray[dataArray.Length - 1];
            if (StringUtil.IsNumeric(version))
            {
                bool isBase64Value = SecurityUtil.IsBase64Value(dataArray[0]);
                if (isBase64Value)
                {
                    if (dataArray.Length == 3)
                    {
                        isBase64Value = SecurityUtil.IsBase64Value(dataArray[1]);
                        if (isBase64Value)
                        {
                            return true;
                        }
                    }
                    else
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 加密手机尾号后8位
        /// </summary>
        /// <param name="data"></param>
        /// <param name="separator"></param>
        /// <param name="secretContext"></param>
        /// <returns></returns>
        public static string EncryptPhone(string data, string separator, SecretContext secretContext)
        {
            if (data.Length < 11)
            {
                return data;
            }
            string prefixNumber = data.Substring(0, data.Length - 8);
            // 取后8位置
            string last8Number = data.Substring(data.Length - 8);

            return separator + prefixNumber + separator + SecurityUtil.AESEncrypt(last8Number, secretContext.Secret) + separator
                    + secretContext.SecretVersion + separator;
        }

        /// <summary>
        /// 加密手机后4位转H-MAC
        /// </summary>
        /// <param name="data"></param>
        /// <param name="separator"></param>
        /// <param name="secretContext"></param>
        /// <returns></returns>
        public static string EncryptPhoneIndex(string data, string separator, SecretContext secretContext)
        {
            if (data.Length < 11)
            {
                return data;
            }
            // 取后4位
            string last4Number = data.Substring(data.Length - 4);
            return separator + SecurityUtil.HmacMD5EncryptToBase64(last4Number, secretContext.Secret) + separator
                    + SecurityUtil.AESEncrypt(data, secretContext.Secret) + separator + secretContext.SecretVersion
                    + separator + separator;
        }

        /// <summary>
        /// 手机号后4位H-MAC值
        /// </summary>
        /// <param name="data"></param>
        /// <param name="separator"></param>
        /// <param name="secretContext"></param>
        /// <returns></returns>
        public static string SearchPhoneIndex(string data, string separator, SecretContext secretContext)
        {
            if (data.Length != 4)
            {
                throw new SecretException("phoneNumber error");
            }
            return separator + SecurityUtil.HmacMD5EncryptToBase64(data, secretContext.Secret) + separator;
        }

        /// <summary>
        ///  生成密文数据
        /// </summary>
        /// <param name="data"></param>
        /// <param name="separator"></param>
        /// <param name="secretContext"></param>
        /// <returns></returns>
        public static string EncryptNormal(string data, string separator, SecretContext secretContext)
        {
            return separator + SecurityUtil.AESEncrypt(data, secretContext.Secret) + separator + secretContext.SecretVersion
                    + separator;
        }

        /// <summary>
        /// 滑窗加密
        /// </summary>
        /// <param name="data"></param>
        /// <param name="compressLen"></param>
        /// <param name="slideSize"></param>
        /// <param name="separator"></param>
        /// <param name="secretContext"></param>
        /// <returns></returns>
        public static string EncryptNormalIndex(string data, int compressLen, int slideSize, string separator,
                SecretContext secretContext)
        {
            List<string> slideList = SecurityUtil.GetSlideWindows(data, slideSize);
            StringBuilder builder = new StringBuilder();
            foreach (string slide in slideList)
            {
                builder.Append(SecurityUtil.HmacMD5EncryptToBase64(slide, secretContext.Secret, compressLen));
            }

            return separator + SecurityUtil.AESEncrypt(data, secretContext.Secret) + separator + builder.ToString() + separator
                    + secretContext.SecretVersion + separator + separator;
        }

        /// <summary>
        /// 密文检索
        /// </summary>
        /// <param name="data"></param>
        /// <param name="compressLen"></param>
        /// <param name="slideSize"></param>
        /// <param name="secretContext"></param>
        /// <returns></returns>
        public static string SearchNormalIndex(string data, int compressLen, int slideSize, SecretContext secretContext)
        {
            List<string> slideList = SecurityUtil.GetSlideWindows(data, slideSize);
            StringBuilder builder = new StringBuilder();
            foreach (string slide in slideList)
            {
                builder.Append(SecurityUtil.HmacMD5EncryptToBase64(slide, secretContext.Secret, compressLen));
            }

            return builder.ToString();
        }

        /// <summary>
        /// 获取秘钥版本、加密原始数据
        /// </summary>
        /// <param name="data"></param>
        /// <param name="separatorChar"></param>
        /// <returns></returns>
        public static SecretData GetSecretData(string data, char separatorChar)
        {
            SecretData secretData = null;
            if (PHONE_SEPARATOR_CHAR == separatorChar)
            {
                string[] dataArray = StringUtil.Split(data, separatorChar);
                if (dataArray.Length != 3)
                {
                    return null;
                }

                string version = dataArray[2];
                if (StringUtil.IsNumeric(version))
                {
                    secretData = new SecretData();
                    secretData.OriginalValue = dataArray[0]; ;// 手机号码前缀
                    secretData.OriginalBase64Value = dataArray[1];
                    secretData.SecretVersion = Convert.ToInt64(version);
                }
            }
            else
            {
                string[] dataArray = StringUtil.Split(data, separatorChar);
                if (dataArray.Length != 2)
                {
                    return null;
                }

                string version = dataArray[1];
                if (StringUtil.IsNumeric(version))
                {
                    secretData = new SecretData();
                    secretData.OriginalBase64Value = dataArray[0];
                    secretData.SecretVersion = Convert.ToInt64(version);
                }
            }
            return secretData;
        }

        /// <summary>
        /// 获取秘钥版本、加密原始数据（支持密文检索）
        /// </summary>
        /// <param name="data"></param>
        /// <param name="separatorChar"></param>
        /// <returns></returns>
        public static SecretData GetIndexSecretData(string data, char separatorChar)
        {
            SecretData secretData = null;
            if (PHONE_SEPARATOR_CHAR == separatorChar)
            {
                string[] dataArray = StringUtil.Split(data, separatorChar);
                if (dataArray.Length != 3)
                {
                    return null;
                }

                string version = dataArray[2];
                if (StringUtil.IsNumeric(version))
                {
                    secretData = new SecretData();
                    secretData.OriginalValue = dataArray[0];// H-MAC(手机号码后4位)
                    secretData.OriginalBase64Value = dataArray[1];
                    secretData.SecretVersion = Convert.ToInt64(version);
                }
            }
            else
            {
                string[] dataArray = StringUtil.Split(data, separatorChar);
                if (dataArray.Length != 3)
                {
                    return null;
                }

                string version = dataArray[2];
                if (StringUtil.IsNumeric(version))
                {
                    secretData = new SecretData();
                    secretData.OriginalBase64Value = dataArray[0];
                    secretData.OriginalValue = dataArray[1];// H-MAC value
                    secretData.SecretVersion = Convert.ToInt64(version);
                }
            }
            if (secretData == null)
            {
                return secretData;
            }

            secretData.Search = true;
            return secretData;
        }

    }
}
