using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Net.Sockets;

namespace linker.messenger.tunnel.stun;

public class HostnameEndpoint
{
	public string Hostname { get; }
	public ushort Port { get; }

	private HostnameEndpoint(string host, ushort port)
	{
		Hostname = host;
		Port = port;
	}

	public static bool TryParse(string s, [NotNullWhen(true)] out HostnameEndpoint? result, ushort defaultPort = 0)
	{
		result = null;
		if (string.IsNullOrEmpty(s))
		{
			return false;
		}

		int hostLength = s.Length;
		int pos = s.LastIndexOf(':');

		if (pos > 0)
		{
			if (s[pos - 1] is ']')
			{
				hostLength = pos;
			}
			else if (s.AsSpan(0, pos).LastIndexOf(':') is -1)
			{
				hostLength = pos;
			}
		}

		string host = s[..hostLength];
		UriHostNameType type = Uri.CheckHostName(host);
		switch (type)
		{
			case UriHostNameType.Dns:
			case UriHostNameType.IPv4:
			case UriHostNameType.IPv6:
			{
				break;
			}
			default:
			{
				return false;
			}
		}

		if (hostLength == s.Length || ushort.TryParse(s.AsSpan(hostLength + 1), out defaultPort))
		{
			result = new HostnameEndpoint(host, defaultPort);
			return true;
		}

		return false;
	}

	public override string ToString()
	{
		if (IPAddress.TryParse(Hostname, out IPAddress? ip) && ip.AddressFamily is AddressFamily.InterNetworkV6)
		{
			return $@"[{ip}]:{Port}";
		}

		return $@"{Hostname}:{Port}";
	}
}
