using FastGithub.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
namespace FastGithub.Dns
{
    /// 
    /// 代理冲突解决者
    /// 
    [SupportedOSPlatform("windows")]
    sealed class ProxyConflictSolver : IConflictSolver
    {
        private const int INTERNET_OPTION_REFRESH = 37;
        private const int INTERNET_OPTION_PROXY_SETTINGS_CHANGED = 95;
        private const char PROXYOVERRIDE_SEPARATOR = ';';
        private const string PROXYOVERRIDE_KEY = "ProxyOverride";
        private const string INTERNET_SETTINGS = @"Software\Microsoft\Windows\CurrentVersion\Internet Settings";
        private readonly IOptions options;
        private readonly ILogger logger;
        [DllImport("wininet.dll")]
        private static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength);
        /// 
        /// 代理冲突解决者
        /// 
        /// 
        /// 
        public ProxyConflictSolver(
            IOptions options,
            ILogger logger)
        {
            this.options = options;
            this.logger = logger;
        }
        /// 
        /// 解决冲突
        /// 
        /// 
        /// 
        public Task SolveAsync(CancellationToken cancellationToken)
        {
            this.SetToProxyOvride();
            this.CheckProxyConflict();
            return Task.CompletedTask;
        }
        /// 
        /// 恢复冲突
        /// 
        /// 
        /// 
        public Task RestoreAsync(CancellationToken cancellationToken)
        {
            this.RemoveFromProxyOvride();
            return Task.CompletedTask;
        }
        /// 
        /// 添加到ProxyOvride
        /// 
        private void SetToProxyOvride()
        {
            using var settings = Registry.CurrentUser.OpenSubKey(INTERNET_SETTINGS, writable: true);
            if (settings == null)
            {
                return;
            }
            var items = this.options.Value.DomainConfigs.Keys.ToHashSet();
            foreach (var item in GetProxyOvride(settings))
            {
                items.Add(item);
            }
            SetProxyOvride(settings, items);
        }
        /// 
        /// 从ProxyOvride移除
        /// 
        private void RemoveFromProxyOvride()
        {
            using var settings = Registry.CurrentUser.OpenSubKey(INTERNET_SETTINGS, writable: true);
            if (settings == null)
            {
                return;
            }
            var proxyOvride = GetProxyOvride(settings);
            var items = proxyOvride.Except(this.options.Value.DomainConfigs.Keys);
            SetProxyOvride(settings, items);
        }
        /// 
        /// 检测代理冲突
        /// 
        private void CheckProxyConflict()
        {
            var systemProxy = HttpClient.DefaultProxy;
            if (systemProxy == null)
            {
                return;
            }
            foreach (var domain in this.options.Value.DomainConfigs.Keys)
            {
                var destination = new Uri($"https://{domain.Replace('*', 'a')}");
                var proxyServer = systemProxy.GetProxy(destination);
                if (proxyServer != null)
                {
                    this.logger.LogError($"由于系统设置了代理{proxyServer},{nameof(FastGithub)}无法加速{domain}");
                }
            }
        }
        /// 
        /// 获取ProxyOverride
        /// 
        /// 
        /// 
        private static string[] GetProxyOvride(RegistryKey registryKey)
        {
            var value = registryKey.GetValue(PROXYOVERRIDE_KEY, null)?.ToString();
            if (value == null)
            {
                return Array.Empty();
            }
            return value
                .Split(PROXYOVERRIDE_SEPARATOR, StringSplitOptions.RemoveEmptyEntries)
                .Select(item => item.Trim())
                .ToArray();
        }
        /// 
        /// 设置ProxyOverride
        /// 
        /// 
        /// 
        private static void SetProxyOvride(RegistryKey registryKey, IEnumerable items)
        {
            var value = string.Join(PROXYOVERRIDE_SEPARATOR, items);
            registryKey.SetValue(PROXYOVERRIDE_KEY, value, RegistryValueKind.String);
            InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY_SETTINGS_CHANGED, IntPtr.Zero, 0);
            InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0);
        }
    }
}