using System.Data.Common;
using ZB.MOM.WW.ScadaBridge.Commons.Types;

namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;

/// <summary>
/// Interface for database access from scripts.
/// Implemented by ExternalSystemGateway, consumed by ScriptRuntimeContext.
/// </summary>
public interface IDatabaseGateway
{
    /// <summary>
    /// Returns an ADO.NET DbConnection (typically SqlConnection) from the named connection.
    /// Connection pooling is managed by the underlying provider.
    /// Caller is responsible for disposing.
    /// </summary>
    /// <param name="connectionName">Name of the configured database connection to open.</param>
    /// <param name="cancellationToken">Cancellation token for the async open operation.</param>
    /// <returns>A task that resolves to an open <see cref="DbConnection"/>; the caller is responsible for disposing it.</returns>
    Task<DbConnection> GetConnectionAsync(
        string connectionName,
        CancellationToken cancellationToken = default);

    /// <summary>
    /// Submits a SQL write to the store-and-forward engine for reliable delivery.
    /// </summary>
    /// <param name="trackedOperationId">
    /// Caller-supplied tracking id used as the
    /// store-and-forward message id so the S&amp;F retry loop can read it
    /// back via <c>StoreAndForwardMessage.Id</c> and emit per-attempt /
    /// terminal cached-write telemetry under the same id. Defaults to
    /// <c>null</c> — when omitted the S&amp;F engine mints a fresh GUID and no
    /// telemetry is correlated.
    /// </param>
    /// <param name="executionId">
    /// The originating script execution's
    /// per-run correlation id. When the write is buffered on a transient
    /// failure this is threaded onto the S&amp;F message so the retry-loop
    /// cached-write audit rows carry it. <c>null</c> when not threaded.
    /// </param>
    /// <param name="sourceScript">
    /// The originating script identifier,
    /// threaded onto the buffered S&amp;F message alongside
    /// <paramref name="executionId"/>. <c>null</c> when not known.
    /// </param>
    /// <param name="parentExecutionId">
    /// The <c>ExecutionId</c> of the
    /// inbound-API request that spawned the originating script execution.
    /// When the write is buffered on a transient failure this is threaded onto
    /// the S&amp;F message alongside <paramref name="executionId"/> so the
    /// retry-loop cached-write audit rows carry it. <c>null</c> for a
    /// non-routed run.
    /// </param>
    /// <param name="connectionName">Name of the configured database connection to write to.</param>
    /// <param name="sql">SQL statement to execute as a store-and-forward write.</param>
    /// <param name="parameters">Optional SQL parameters for the statement.</param>
    /// <param name="originInstanceName">Optional name of the instance that originated the write.</param>
    /// <param name="cancellationToken">Cancellation token for the buffering operation.</param>
    /// <returns>
    /// An <see cref="ExternalCallResult"/> mirroring the External-System
    /// API path (<c>IExternalSystemClient.CachedCallAsync</c>). The write is
    /// attempted immediately:
    /// <list type="bullet">
    ///   <item>immediate success → <c>Success=true, WasBuffered=false</c> (not buffered);</item>
    ///   <item>permanent SQL error (constraint / syntax / permission) → <c>Success=false, WasBuffered=false</c> with an error message, returned synchronously and NOT buffered;</item>
    ///   <item>transient SQL error (connection / timeout / deadlock / throttle) → buffered to store-and-forward, <c>Success=true, WasBuffered=true</c>.</item>
    /// </list>
    /// </returns>
    Task<ExternalCallResult> CachedWriteAsync(
        string connectionName,
        string sql,
        IReadOnlyDictionary<string, object?>? parameters = null,
        string? originInstanceName = null,
        CancellationToken cancellationToken = default,
        TrackedOperationId? trackedOperationId = null,
        Guid? executionId = null,
        string? sourceScript = null,
        Guid? parentExecutionId = null);
}
