using Microsoft.AspNetCore.Http;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;

namespace Admin.Core.Common
{
    public static class IpHelper
    {
        /// <summary>
        /// 获取当前IP地址
        /// </summary>
        /// <param name="preferredNetworks"></param>
        /// <returns></returns>
        public static string GetCurrentIp(string preferredNetworks)
        {
            var instanceIp = "127.0.0.1";

            try
            {
                // 获取可用网卡
                var nics = NetworkInterface.GetAllNetworkInterfaces()?.Where(network => network.OperationalStatus == OperationalStatus.Up);

                // 获取所有可用网卡IP信息
                var ipCollection = nics?.Select(x => x.GetIPProperties())?.SelectMany(x => x.UnicastAddresses);

                foreach (var ipadd in ipCollection)
                {
                    if (!IPAddress.IsLoopback(ipadd.Address) && ipadd.Address.AddressFamily == AddressFamily.InterNetwork)
                    {
                        if (string.IsNullOrEmpty(preferredNetworks))
                        {
                            instanceIp = ipadd.Address.ToString();
                            break;
                        }

                        if (!ipadd.Address.ToString().StartsWith(preferredNetworks)) continue;
                        instanceIp = ipadd.Address.ToString();
                        break;
                    }
                }
            }
            catch
            {
                // ignored
            }
            if (!instanceIp.IsNotEmptyOrNull() || Encoding.Default.GetByteCount(instanceIp) < 9)
            {
                instanceIp = "127.0.0.1";
            }
            return instanceIp;
        }

        public static string GetIpAddr(HttpContext httpContext)
        {
            var request = httpContext.Request;
            if (request == null)
            {
                return "unknown";
            }
            string ip = request.Headers["x-forwarded-for"];
            if (string.ReferenceEquals(ip, null) || ip.Length == 0 || "unknown".Equals(ip.ToLower()))
            {
                ip = request.Headers["Proxy-Client-IP"];
            }
            if (string.ReferenceEquals(ip, null) || ip.Length == 0 || "unknown".Equals(ip.ToLower()))
            {
                ip = request.Headers["X-Forwarded-For"];
            }
            if (string.ReferenceEquals(ip, null) || ip.Length == 0 || "unknown".Equals(ip.ToLower()))
            {
                ip = request.Headers["WL-Proxy-Client-IP"];
            }
            if (string.ReferenceEquals(ip, null) || ip.Length == 0 || "unknown".Equals(ip.ToLower()))
            {
                ip = request.Headers["X-Real-IP"];
            }
            if (!ip.IsNotEmptyOrNull() || Encoding.Default.GetByteCount(ip) < 9)
            {
                return "127.0.0.1";
            }
            return "0:0:0:0:0:0:0:1".Equals(ip) ? "127.0.0.1" : ip;
        }

        public static bool InternalIp(string ip)
        {
            sbyte[] addr = TextToNumericFormatV4(ip);
            return InternalIp(addr) || "127.0.0.1".Equals(ip);
        }

        private static bool InternalIp(sbyte[] addr)
        {
            if (addr.IsNotEmptyOrNull() || addr.Length < 2)
            {
                return true;
            }
            sbyte b0 = addr[0];
            sbyte b1 = addr[1];
            const sbyte SECTION_1 = 0x0A;
            sbyte SECTION_2 = unchecked((sbyte)0xAC);
            sbyte SECTION_3 = (sbyte)0x10;
            sbyte SECTION_4 = (sbyte)0x1F;
            sbyte SECTION_5 = unchecked((sbyte)0xC0);
            sbyte SECTION_6 = unchecked((sbyte)0xA8);
            if (b0 == SECTION_1) return true;
            if (b0 == SECTION_2 && b1 >= SECTION_3 && b1 <= SECTION_4) return true;
            if (b0 == SECTION_5 && b1 == SECTION_6) return true;

            return false;
        }

        /// <summary>
        /// 将IPv4地址转换成字节
        /// </summary>
        /// <param name="text"> IPv4地址 </param>
        /// <returns> byte 字节 </returns>
        public static sbyte[] TextToNumericFormatV4(string text)
        {
            if (text.Length == 0)
            {
                return null;
            }

            sbyte[] bytes = new sbyte[4];
            string[] elements = text.Split('.');
            try
            {
                long l;
                int i;
                switch (elements.Length)
                {
                    case 1:
                        l = long.Parse(elements[0]);
                        if ((l < 0L) || (l > 4294967295L))
                        {
                            return null;
                        }
                        bytes[0] = (sbyte)(int)(l >> 24 & 0xFF);
                        bytes[1] = (sbyte)(int)((l & 0xFFFFFF) >> 16 & 0xFF);
                        bytes[2] = (sbyte)(int)((l & 0xFFFF) >> 8 & 0xFF);
                        bytes[3] = (sbyte)(int)(l & 0xFF);
                        break;
                    case 2:
                        l = int.Parse(elements[0]);
                        if ((l < 0L) || (l > 255L))
                        {
                            return null;
                        }
                        bytes[0] = (sbyte)(int)(l & 0xFF);
                        l = int.Parse(elements[1]);
                        if ((l < 0L) || (l > 16777215L))
                        {
                            return null;
                        }
                        bytes[1] = (sbyte)(int)(l >> 16 & 0xFF);
                        bytes[2] = (sbyte)(int)((l & 0xFFFF) >> 8 & 0xFF);
                        bytes[3] = (sbyte)(int)(l & 0xFF);
                        break;
                    case 3:
                        for (i = 0; i < 2; ++i)
                        {
                            l = int.Parse(elements[i]);
                            if ((l < 0L) || (l > 255L))
                            {
                                return null;
                            }
                            bytes[i] = (sbyte)(int)(l & 0xFF);
                        }
                        l = int.Parse(elements[2]);
                        if ((l < 0L) || (l > 65535L))
                        {
                            return null;
                        }
                        bytes[2] = (sbyte)(int)(l >> 8 & 0xFF);
                        bytes[3] = (sbyte)(int)(l & 0xFF);
                        break;
                    case 4:
                        for (i = 0; i < 4; ++i)
                        {
                            l = int.Parse(elements[i]);
                            if ((l < 0L) || (l > 255L))
                            {
                                return null;
                            }
                            bytes[i] = (sbyte)(int)(l & 0xFF);
                        }
                        break;
                    default:
                        return null;
                }
            }
            catch (System.FormatException)
            {
                return null;
            }
            return bytes;
        }


    }
}