using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Runtime.Historian;

namespace ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Tests;

/// <summary>
/// Read-cutover seam tests (T10). Both assert offline construction only — the package client builds
/// its <c>GrpcChannel</c> lazily, so neither the adapter ctor nor the factory dials the gateway. A
/// bogus/unreachable endpoint must therefore construct without throwing or performing network I/O.
/// </summary>
public sealed class HistorianGatewayClientAdapterTests
{
    [Fact]
    public void Adapter_constructs_from_options_without_dialing()
    {
        // Constructing the channel must not perform network I/O (lazy connect).
        var opts = new ServerHistorianOptions { Enabled = true, Endpoint = "https://localhost:5222", ApiKey = "histgw_x_y" };
        using var adapter = HistorianGatewayClientAdapter.Create(opts, NullLoggerFactory.Instance);
        Assert.NotNull(adapter);
    }

    /// <summary>
    ///     A plaintext <c>h2c</c> gateway (an <c>http://</c> endpoint with <c>UseTls=false</c>) must
    ///     construct, using nothing but documented defaults.
    /// </summary>
    /// <remarks>
    ///     <para>
    ///         Found by the LocalDb Phase 2 live gate, on the third consecutive crash-loop of the rig.
    ///         <c>docs/Historian.md</c> and CLAUDE.md both document <c>http://</c> as a supported
    ///         transport ("scheme selects transport: https = TLS, http = h2c"), but it was in fact
    ///         <b>unreachable</b>: this factory forwarded the TLS-only options unconditionally, and
    ///         <see cref="ServerHistorianOptions.AllowUntrustedServerCertificate"/> defaults to
    ///         <see langword="false"/>, so it always sent <c>RequireCertificateValidation=true</c> —
    ///         which the client rejects outright when <c>UseTls=false</c>
    ///         ("RequireCertificateValidation is a TLS-only option and requires UseTls=true").
    ///     </para>
    ///     <para>
    ///         So <b>every</b> h2c deployment crashed at startup, and the only way to avoid it was to
    ///         set <c>AllowUntrustedServerCertificate=true</c> — asserting a certificate posture for a
    ///         connection that has no certificate at all.
    ///     </para>
    /// </remarks>
    [Fact]
    public void Adapter_constructs_for_plaintext_h2c_endpoint()
    {
        var opts = new ServerHistorianOptions
        {
            Enabled = true, Endpoint = "http://localhost:5222", ApiKey = "histgw_x_y", UseTls = false,
        };

        using var adapter = HistorianGatewayClientAdapter.Create(opts, NullLoggerFactory.Instance);

        adapter.ShouldNotBeNull();
    }

    /// <summary>
    ///     A pinned CA path is likewise TLS-only, and must not leak into an h2c client — the same
    ///     rejection, reached by a different field.
    /// </summary>
    [Fact]
    public void Adapter_ignores_tls_only_settings_on_a_plaintext_endpoint()
    {
        var opts = new ServerHistorianOptions
        {
            Enabled = true,
            Endpoint = "http://localhost:5222",
            ApiKey = "histgw_x_y",
            UseTls = false,
            CaCertificatePath = "/etc/ssl/certs/leftover-from-a-tls-config.pem",
        };

        using var adapter = HistorianGatewayClientAdapter.Create(opts, NullLoggerFactory.Instance);

        adapter.ShouldNotBeNull();
    }

    /// <summary>
    /// archreview 06/S-11 — an enabled historian with an empty <c>Endpoint</c> must fail with a
    /// named, config-key-carrying <see cref="InvalidOperationException"/> (defense-in-depth for any
    /// caller that bypasses the Host's <c>ServerHistorianOptionsValidator</c>), not the raw
    /// <see cref="UriFormatException"/> that <c>new Uri("")</c> throws deep in the factory. Current
    /// code throws <see cref="UriFormatException"/> → this is the failing-first (RED) repro.
    /// </summary>
    [Fact]
    public void Create_with_empty_endpoint_throws_named_config_error()
    {
        var opts = new ServerHistorianOptions { Enabled = true, Endpoint = "", ApiKey = "histgw_x_y" };

        var ex = Should.Throw<InvalidOperationException>(
            () => HistorianGatewayClientAdapter.Create(opts, NullLoggerFactory.Instance));
        ex.Message.ShouldContain("ServerHistorian:Endpoint");
    }

    /// <summary>
    /// archreview 06/S-11 companion — a non-empty but unparseable / non-absolute <c>Endpoint</c> must
    /// also fail with the same named <see cref="InvalidOperationException"/>, not a raw
    /// <see cref="UriFormatException"/>. RED on current code.
    /// </summary>
    [Fact]
    public void Create_with_malformed_endpoint_throws_named_config_error()
    {
        var opts = new ServerHistorianOptions { Enabled = true, Endpoint = "not a uri", ApiKey = "histgw_x_y" };

        var ex = Should.Throw<InvalidOperationException>(
            () => HistorianGatewayClientAdapter.Create(opts, NullLoggerFactory.Instance));
        ex.Message.ShouldContain("ServerHistorian:Endpoint");
    }

    [Fact]
    public void Factory_builds_GatewayHistorianDataSource()
    {
        var opts = new ServerHistorianOptions { Enabled = true, Endpoint = "https://localhost:5222", ApiKey = "histgw_x_y" };
        using var services = new ServiceCollection().BuildServiceProvider();
        var dataSource = GatewayHistorian.CreateDataSource(opts, services);
        Assert.IsType<GatewayHistorianDataSource>(dataSource);
    }
}
