using DNS.Client.RequestResolver;
using DNS.Protocol;
using DNS.Protocol.ResourceRecords;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
namespace FastGithub.Dns
{
    /// 
    /// dns解析者
    ///  
    sealed class RequestResolver : IRequestResolver
    {
        private IRequestResolver requestResolver;
        private readonly TimeSpan ttl = TimeSpan.FromMinutes(1d);
        private readonly FastGithubConfig fastGithubConfig;
        private readonly ILogger logger;
        /// 
        /// dns解析者
        /// 
        /// 
        /// 
        /// 
        public RequestResolver(
            FastGithubConfig fastGithubConfig,
            IOptionsMonitor options,
            ILogger logger)
        {
            this.fastGithubConfig = fastGithubConfig;
            this.logger = logger;
            this.requestResolver = new UdpRequestResolver(fastGithubConfig.FastDns);
            options.OnChange(opt => OptionsChanged(opt));
            void OptionsChanged(FastGithubOptions opt)
            {
                var dns = opt.FastDns.ToIPEndPoint();
                this.requestResolver = new UdpRequestResolver(dns);
            }
        }
        /// 
        /// 解析域名
        /// 
        /// 
        /// 
        /// 
        public async Task Resolve(IRequest request, CancellationToken cancellationToken = default)
        {
            var response = Response.FromRequest(request);
            if (request is not RemoteEndPointRequest remoteEndPointRequest)
            {
                return response;
            }
            var question = request.Questions.FirstOrDefault();
            if (question == null || question.Type != RecordType.A)
            {
                return response;
            }
            // 解析匹配的域名指向本机ip
            var domain = question.Name;
            if (this.fastGithubConfig.IsMatch(domain.ToString()) == true)
            {
                var localAddress = remoteEndPointRequest.GetLocalAddress() ?? IPAddress.Loopback;
                var record = new IPAddressResourceRecord(domain, localAddress, this.ttl);
                response.AnswerRecords.Add(record);
                this.logger.LogInformation($"[{domain}->{localAddress}]");
                return response;
            }
            return await this.requestResolver.Resolve(request, cancellationToken);
        }
    }
}