namespace ZB.MOM.WW.OtOpcUa.Driver.FOCAS;

/// <summary>
///     Wire-layer abstraction over one FOCAS session to a CNC. The driver holds one per
///     configured device; lifetime matches the device.
/// </summary>
/// <remarks>
///     <para><b>No default wire implementation ships with this assembly.</b> FWLIB
///     (<c>Fwlib32.dll</c>) is Fanuc-proprietary and requires a valid customer license — it
///     cannot legally be redistributed. The deployment team supplies an
///     <see cref="IFocasClientFactory"/> that wraps the licensed <c>Fwlib32.dll</c> via
///     P/Invoke and registers it at server startup.</para>
///
///     <para>The default <see cref="UnimplementedFocasClientFactory"/> throws with a pointer at
///     the deployment docs so misconfigured servers fail fast with a clear error rather than
///     mysteriously hanging.</para>
/// </remarks>
public interface IFocasClient : IDisposable
{
    /// <summary>Open the FWLIB handle + TCP session. Idempotent.</summary>
    Task ConnectAsync(FocasHostAddress address, TimeSpan timeout, CancellationToken cancellationToken);

    /// <summary>True when the FWLIB handle is valid + the socket is up.</summary>
    bool IsConnected { get; }

    /// <summary>
    ///     Read the value at <paramref name="address"/> in the requested
    ///     <paramref name="type"/>. Returns a boxed .NET value + the OPC UA status mapped
    ///     through <see cref="FocasStatusMapper"/>.
    /// </summary>
    Task<(object? value, uint status)> ReadAsync(
        FocasAddress address,
        FocasDataType type,
        CancellationToken cancellationToken);

    /// <summary>
    ///     Write <paramref name="value"/> to <paramref name="address"/>. Returns the mapped
    ///     OPC UA status (0 = Good).
    /// </summary>
    Task<uint> WriteAsync(
        FocasAddress address,
        FocasDataType type,
        object? value,
        CancellationToken cancellationToken);

    /// <summary>
    ///     Cheap health probe — e.g. <c>cnc_rdcncstat</c>. Returns <c>true</c> when the CNC
    ///     responds with any valid status.
    /// </summary>
    Task<bool> ProbeAsync(CancellationToken cancellationToken);
}

/// <summary>Factory for <see cref="IFocasClient"/>s. One client per configured device.</summary>
public interface IFocasClientFactory
{
    IFocasClient Create();
}

/// <summary>
///     Default factory that throws at construction time — the deployment must register a real
///     factory. Keeps the driver assembly licence-clean while still allowing the skeleton to
///     compile + the abstraction tests to run.
/// </summary>
public sealed class UnimplementedFocasClientFactory : IFocasClientFactory
{
    public IFocasClient Create() => throw new NotSupportedException(
        "FOCAS driver has no wire client configured. Register a real IFocasClientFactory at " +
        "server startup wrapping the licensed Fwlib32.dll — see docs/v2/focas-deployment.md. " +
        "Fanuc licensing forbids shipping Fwlib32.dll in the OtOpcUa package.");
}
