using Opc.Ua;
using Opc.Ua.Client;
using Serilog;

namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Adapters;

/// <summary>
///     Production endpoint discovery that queries the real server.
/// </summary>
internal sealed class DefaultEndpointDiscovery : IEndpointDiscovery
{
    private static readonly ILogger Logger = Log.ForContext<DefaultEndpointDiscovery>();

    public EndpointDescription SelectEndpoint(ApplicationConfiguration config, string endpointUrl,
        MessageSecurityMode requestedMode)
    {
        if (requestedMode == MessageSecurityMode.None)
        {
#pragma warning disable CS0618 // Acceptable for endpoint selection
            return CoreClientUtils.SelectEndpoint(config, endpointUrl, false);
#pragma warning restore CS0618
        }

        using var client = DiscoveryClient.Create(new Uri(endpointUrl));
        var allEndpoints = client.GetEndpoints(null);

        EndpointDescription? best = null;

        foreach (var ep in allEndpoints)
        {
            if (ep.SecurityMode != requestedMode)
                continue;

            if (best == null)
            {
                best = ep;
                continue;
            }

            if (ep.SecurityPolicyUri == SecurityPolicies.Basic256Sha256)
                best = ep;
        }

        if (best == null)
        {
            var available = string.Join(", ", allEndpoints.Select(e => $"{e.SecurityMode}/{e.SecurityPolicyUri}"));
            throw new InvalidOperationException(
                $"No endpoint found with security mode '{requestedMode}'. Available endpoints: {available}");
        }

        // Rewrite endpoint URL hostname to match user-supplied hostname
        var serverUri = new Uri(best.EndpointUrl);
        var requestedUri = new Uri(endpointUrl);
        if (serverUri.Host != requestedUri.Host)
        {
            var builder = new UriBuilder(best.EndpointUrl) { Host = requestedUri.Host };
            best.EndpointUrl = builder.ToString();
            Logger.Debug("Rewrote endpoint host from {ServerHost} to {RequestedHost}", serverUri.Host,
                requestedUri.Host);
        }

        return best;
    }
}