using FastGithub.Configuration;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
namespace FastGithub.DomainResolve
{
    /// 
    /// 域名的IP测速服务
    /// 
    sealed class DomainSpeedTester
    {
        private const string DOMAINS_JSON_FILE = "domains.json";
        private readonly DnsClient dnsClient;
        private readonly object syncRoot = new();
        private readonly Dictionary domainIPAddressHashSet = new();
        /// 
        /// 域名的IP测速服务
        /// 
        /// 
        public DomainSpeedTester(DnsClient dnsClient)
        {
            this.dnsClient = dnsClient;
        }
        /// 
        /// 添加要测速的域名
        /// 
        /// 
        /// 
        public bool Add(string domain)
        {
            lock (this.syncRoot)
            {
                return this.domainIPAddressHashSet.TryAdd(domain, new IPAddressItemHashSet());
            }
        }
        /// 
        /// 获取测试后排序的IP
        /// 
        /// 
        /// 
        public IPAddress[] GetIPAddresses(string domain)
        {
            lock (this.syncRoot)
            {
                if (this.domainIPAddressHashSet.TryGetValue(domain, out var hashSet) && hashSet.Count > 0)
                {
                    return hashSet.ToArray().OrderBy(item => item.PingElapsed).Select(item => item.Address).ToArray();
                }
                return Array.Empty();
            }
        }
        /// 
        /// 加载域名数据
        /// 
        /// 
        /// 
        public async Task LoadDomainsAsync(CancellationToken cancellationToken)
        {
            if (File.Exists(DOMAINS_JSON_FILE) == false)
            {
                return;
            }
            using var fileStream = File.OpenRead(DOMAINS_JSON_FILE);
            var domains = await JsonSerializer.DeserializeAsync(fileStream, cancellationToken: cancellationToken);
            if (domains == null)
            {
                return;
            }
            lock (this.syncRoot)
            {
                foreach (var domain in domains)
                {
                    this.domainIPAddressHashSet.TryAdd(domain, new IPAddressItemHashSet());
                }
            }
        }
        /// 
        /// 保存域名数据
        /// 
        /// 
        public async Task SaveDomainsAsync()
        {
            var domains = this.domainIPAddressHashSet.Keys
                .Select(item => new DomainPattern(item))
                .OrderBy(item => item)
                .Select(item => item.ToString())
                .ToArray();
            try
            {
                using var fileStream = File.OpenWrite(DOMAINS_JSON_FILE);
                await JsonSerializer.SerializeAsync(fileStream, domains, new JsonSerializerOptions { WriteIndented = true });
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
        /// 
        /// 进行一轮IP测速
        /// 
        /// 
        /// 
        public async Task TestSpeedAsync(CancellationToken cancellationToken)
        {
            KeyValuePair[] keyValues;
            lock (this.syncRoot)
            {
                keyValues = this.domainIPAddressHashSet.ToArray();
            }
            foreach (var keyValue in keyValues)
            {
                var domain = keyValue.Key;
                var hashSet = keyValue.Value;
                await foreach (var address in this.dnsClient.ResolveAsync(domain, cancellationToken))
                {
                    hashSet.Add(new IPAddressItem(address));
                }
                await hashSet.PingAllAsync();
            }
        }
    }
}