using System.Net.Sockets;

namespace ZB.MOM.WW.OtOpcUa.Host.IntegrationTests;

/// <summary>
///     Lightweight TCP-connect probe used by E2E integration tests to detect whether a Docker
///     fixture is reachable before attempting live work. Tests skip cleanly when this returns
///     <c>false</c>; CI with fixtures available lets them run.
/// </summary>
public static class DockerFixtureAvailability
{
    /// <summary>
    ///     Attempts a TCP connect to <paramref name="host"/>:<paramref name="port"/>. Returns
    ///     <c>true</c> if the connection is accepted within <paramref name="timeoutMs"/>
    ///     milliseconds; <c>false</c> on refusal, timeout, or DNS failure.
    /// </summary>
    /// <param name="host">The host to probe.</param>
    /// <param name="port">The TCP port to connect to.</param>
    /// <param name="timeoutMs">Maximum time to wait in milliseconds; defaults to 500.</param>
    public static bool IsReachable(string host, int port, int timeoutMs = 500)
    {
        try
        {
            // Force IPv4 — remote Docker host binds only on IPv4 (0.0.0.0).
            using var client = new TcpClient(AddressFamily.InterNetwork);
            var ipv4 = System.Net.Dns.GetHostAddresses(host)
                .FirstOrDefault(a => a.AddressFamily == AddressFamily.InterNetwork)
                ?? System.Net.IPAddress.Parse(host);

            var task = client.ConnectAsync(ipv4, port);
            return task.Wait(timeoutMs) && client.Connected;
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    ///     Parses an <c>HOST:PORT</c> endpoint string and probes reachability.
    ///     Returns <c>true</c> if the connection succeeds within <paramref name="timeoutMs"/>
    ///     milliseconds. Handles malformed strings gracefully by returning <c>false</c>.
    /// </summary>
    /// <param name="endpoint">Endpoint in <c>host:port</c> format.</param>
    /// <param name="timeoutMs">Maximum time to wait in milliseconds; defaults to 500.</param>
    public static bool IsReachable(string endpoint, int timeoutMs = 500)
    {
        try
        {
            var parts = endpoint.Split(':', 2);
            if (parts.Length != 2 || !int.TryParse(parts[1], out var port))
                return false;
            return IsReachable(parts[0], port, timeoutMs);
        }
        catch
        {
            return false;
        }
    }
}
