using ZB.MOM.WW.OtOpcUa.Commons.Interfaces;
using ZB.MOM.WW.OtOpcUa.Commons.Messages.Admin;

namespace ZB.MOM.WW.OtOpcUa.AdminUI.Clients;

/// <summary>
///     Thin AdminUI-side wrapper for the Test Connect operation. Dispatches a
///     <see cref="TestDriverConnect"/> through <c>IAdminOperationsClient</c>, applies a
///     65-second outer wall (the actor itself clamps to [1,60]s; this guards against the
///     Ask never replying), and surfaces a friendly result for the Razor button to render.
/// </summary>
public sealed class AdminProbeService
{
    private readonly IAdminOperationsClient _client;

    /// <summary>Initializes a new instance of the <see cref="AdminProbeService"/>.</summary>
    /// <param name="client">The admin operations client used to dispatch probe requests.</param>
    public AdminProbeService(IAdminOperationsClient client) => _client = client;

    /// <summary>
    ///     Dispatches a Test Connect probe for the supplied driver type and config JSON,
    ///     waiting up to 65 seconds for a reply before surfacing a timeout failure.
    /// </summary>
    /// <param name="driverType">Driver type key (must match an installed <c>IDriverProbe.DriverType</c>).</param>
    /// <param name="configJson">Driver config as JSON (same shape as <c>DriverInstance.DriverConfig</c>).</param>
    /// <param name="timeoutSeconds">Per-probe timeout; actor clamps to [1, 60].</param>
    /// <param name="ct">Optional cancellation token from the caller.</param>
    /// <returns>The probe result, or a timeout failure if no reply arrives in time.</returns>
    public async Task<TestDriverConnectResult> TestAsync(
        string driverType,
        string configJson,
        int timeoutSeconds,
        CancellationToken ct = default)
    {
        var correlationId = Guid.NewGuid();
        var msg = new TestDriverConnect(driverType, configJson, timeoutSeconds, correlationId);

        // 65s outer guard — the actor's CTS clamps to 60s; if the Ask never returns we still want
        // a deterministic failure surface for the UI.
        using var outerCts = CancellationTokenSource.CreateLinkedTokenSource(ct);
        outerCts.CancelAfter(TimeSpan.FromSeconds(65));

        try
        {
            return await _client.AskAsync<TestDriverConnectResult>(msg, outerCts.Token);
        }
        catch (OperationCanceledException)
        {
            return new TestDriverConnectResult(false, "Probe request did not return within 65s.", null, correlationId);
        }
        catch (Exception ex)
        {
            return new TestDriverConnectResult(false, $"Probe dispatch failed: {ex.Message}", null, correlationId);
        }
    }
}
