using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace FastGithub.Scanner.LookupProviders
{
    /// 
    /// ipaddress.com的域名与ip关系提供者
    /// 
    [Service(ServiceLifetime.Singleton, ServiceType = typeof(IGithubLookupProvider))]
    sealed class IPAddressComProvider : IGithubLookupProvider
    {
        private readonly IOptionsMonitor options;
        private readonly IHttpClientFactory httpClientFactory;
        private readonly ILogger logger;
        private readonly Uri lookupUri = new("https://www.ipaddress.com/ip-lookup");
        /// 
        /// 获取排序
        /// 
        public int Order => default;
        /// 
        /// ipaddress.com的域名与ip关系提供者
        /// 
        /// 
        /// 
        public IPAddressComProvider(
            IOptionsMonitor options,
            IHttpClientFactory httpClientFactory,
            ILogger logger)
        {
            this.options = options;
            this.httpClientFactory = httpClientFactory;
            this.logger = logger;
        }
        /// 
        /// 查找域名与ip关系
        /// 
        /// 
        /// 
        /// 
        public async Task> LookupAsync(IEnumerable domains, CancellationToken cancellationToken)
        {
            var setting = this.options.CurrentValue;
            if (setting.Enable == false)
            {
                return Enumerable.Empty();
            }
            var httpClient = this.httpClientFactory.CreateClient(nameof(Scanner));
            var result = new HashSet();
            foreach (var domain in domains)
            {
                try
                {
                    var addresses = await this.LookupAsync(httpClient, domain, cancellationToken);
                    foreach (var address in addresses)
                    {
                        result.Add(new DomainAddress(domain, address));
                    }
                }
                catch (Exception)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    this.logger.LogWarning($"ipaddress.com无法解析{domain}");
                }
            }
            return result;
        }
        /// 
        /// 反查ip
        /// 
        /// 
        /// 
        /// 
        private async Task> LookupAsync(HttpClient httpClient, string domain, CancellationToken cancellationToken)
        {
            using var request = new HttpRequestMessage
            {
                Method = HttpMethod.Post,
                RequestUri = lookupUri,
                Content = new StringContent($"host={domain}", Encoding.UTF8, "application/x-www-form-urlencoded")
            };
            using var response = await httpClient.SendAsync(request, cancellationToken);
            var html = await response.Content.ReadAsStringAsync(cancellationToken);
            var match = Regex.Match(html, @"(?<=IP Lookup : )\d+\.\d+\.\d+\.\d+", RegexOptions.IgnoreCase);
            if (match.Success && IPAddress.TryParse(match.Value, out var address))
            {
                return new List { address };
            }
            var prefix = Regex.Escape("type=\"radio\" value=\"");
            var matches = Regex.Matches(html, @$"(?<={prefix})\d+\.\d+\.\d+\.\d+", RegexOptions.IgnoreCase);
            var addressList = new List();
            foreach (Match item in matches)
            {
                if (IPAddress.TryParse(item.Value, out address))
                {
                    addressList.Add(address);
                }
            }
            return addressList;
        }
    }
}