using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Net.Sockets;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace FastGithub.Scanner.DomainAddressProviders
{
    /// 
    /// Github公开的域名与ip关系提供者
    /// 
    [Service(ServiceLifetime.Singleton, ServiceType = typeof(IDomainAddressProvider))]
    sealed class GithubMetaProvider : IDomainAddressProvider
    {
        private readonly IOptionsMonitor options;
        private readonly ILogger logger;
        /// 
        /// Github公开的域名与ip关系提供者
        /// 
        /// 
        /// 
        public GithubMetaProvider(
            IOptionsMonitor options,
            ILogger logger)
        {
            this.options = options;
            this.logger = logger;
        }
        /// 
        /// 创建域名与ip的关系
        /// 
        /// 
        public async Task> CreateDomainAddressesAsync()
        {
            var setting = this.options.CurrentValue.DominAddressProviders.GithubMetaProvider;
            if (setting.Enable == false)
            {
                return Enumerable.Empty();
            }
            try
            {
                using var httpClient = new HttpClient();
                var meta = await httpClient.GetFromJsonAsync(setting.MetaUri);
                if (meta != null)
                {
                    return meta.ToDomainAddresses();
                }
            }
            catch (Exception ex)
            {
                this.logger.LogWarning($"加载远程的ip列表异常:{ex.Message}");
            }
            return Enumerable.Empty();
        }
        /// 
        /// github的meta结构
        /// 
        private class Meta
        {
            [JsonPropertyName("web")]
            public string[] Web { get; set; } = Array.Empty();
            /// 
            /// 转换为域名与ip关系
            /// 
            /// 
            public IEnumerable ToDomainAddresses()
            {
                foreach (var range in IPAddressRange.From(this.Web).OrderBy(item => item.Size))
                {
                    if (range.AddressFamily == AddressFamily.InterNetwork)
                    {
                        foreach (var address in range)
                        {
                            yield return new DomainAddress("github.com", address);
                        }
                    }
                }
            }
        }
    }
}