using Newtonsoft.Json;
using skyscraper5.DNS.Protocol;
using skyscraper5.DNS.Protocol.ResourceRecords;
using skyscraper5.DNS.Protocol.ResourceRecords.Records;
using skyscraper5.Skyscraper.Plugins;
using skyscraper5.src.Skyscraper.Scraper.Dns;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace skyscraper5.DNS
{
	[SkyscraperPlugin]
	internal class PluginDns : IDnsParser
	{
		public DnsParseResult Parse(byte[] data)
		{
			Header header = Header.FromArray(data);
			if (!header.Response)
				return new DnsParseResult();

			Response response = Response.FromArray(data);
			if (response.AnswerRecords.Count == 0)
				return new DnsParseResult();

			DnsParseResult result = new DnsParseResult();
			result.Records = new List<DnsRecord>();
			result.Records.AddRange(response.AnswerRecords.Where(x => x != null).Select(x => SanitizeDnsRecord(x)));
			result.Records.AddRange(response.AdditionalRecords.Where(x => x != null).Select(x => SanitizeDnsRecord(x)));

			return result;
		}

		private DnsRecord SanitizeDnsRecord(IResourceRecord record)
		{
			DnsRecord result = new DnsRecord();
			result.Domain = record.Name.ToString();
			result.RecordType = new Tuple<int, string>((int)record.Type, record.Type.ToString());
			result.TTL = record.TimeToLive;
			result.ResourceData = ResourceDataToString(record);
			result.IP = ExtractIpAddress(record);
			return result;
		}

		private string ResourceDataToString(IResourceRecord record)
		{
			SimpleDnsRecord simpleDnsRecord = record as SimpleDnsRecord;
			if (simpleDnsRecord != null)
			{
				return simpleDnsRecord.GetDataAsString();
			}
			OptionRecord optionRecord = record as OptionRecord;
			if (optionRecord != null)
			{
				string optionsJson = JsonConvert.SerializeObject(optionRecord.Options);
				return optionsJson;
			}
			NamingAuthorityPointerResourceRecord namingAuthorityPointerResourceRecord = record as NamingAuthorityPointerResourceRecord;
			if (namingAuthorityPointerResourceRecord != null)
			{
				string naprr = namingAuthorityPointerResourceRecord.Name.ToString();
				return naprr;
            }
			NameServerResourceRecord nameServerResourceRecord = record as NameServerResourceRecord;
			if (nameServerResourceRecord != null)
			{
				string nsrr = nameServerResourceRecord.NSDomainName.ToString();
				return nsrr;
			}
			MailExchangeResourceRecord mxRecord = record as MailExchangeResourceRecord;
			if (mxRecord != null)
			{
				string mxrr = JsonConvert.SerializeObject(new
				{
					Preference = mxRecord.Preference,
					ExchangeDomainName = mxRecord.ExchangeDomainName.ToString()
				});
				return mxrr;
			}
			throw new NotImplementedException(record.GetType().Name.ToString());
		}

		private IPAddress ExtractIpAddress(IResourceRecord record)
		{
			IPAddressResourceRecord iparr = record as IPAddressResourceRecord;
			if (iparr != null)
			{
				return iparr.IPAddress;
			}
			return null;
		}
	}
}
