using ScadaLink.Commons.Types.Enums;

namespace ScadaLink.Commons.Interfaces.Protocol;

public enum QualityCode { Good, Bad, Uncertain }

public record TagValue(object? Value, QualityCode Quality, DateTimeOffset Timestamp);
public record ReadResult(bool Success, TagValue? Value, string? ErrorMessage);
public record WriteResult(bool Success, string? ErrorMessage);

public delegate void SubscriptionCallback(string tagPath, TagValue value);

public interface IDataConnection : IAsyncDisposable
{
    Task ConnectAsync(IDictionary<string, string> connectionDetails, CancellationToken cancellationToken = default);
    Task DisconnectAsync(CancellationToken cancellationToken = default);
    Task<string> SubscribeAsync(string tagPath, SubscriptionCallback callback, CancellationToken cancellationToken = default);
    Task UnsubscribeAsync(string subscriptionId, CancellationToken cancellationToken = default);
    Task<ReadResult> ReadAsync(string tagPath, CancellationToken cancellationToken = default);
    Task<IReadOnlyDictionary<string, ReadResult>> ReadBatchAsync(IEnumerable<string> tagPaths, CancellationToken cancellationToken = default);
    Task<WriteResult> WriteAsync(string tagPath, object? value, CancellationToken cancellationToken = default);
    Task<IReadOnlyDictionary<string, WriteResult>> WriteBatchAsync(IDictionary<string, object?> values, CancellationToken cancellationToken = default);
    Task<bool> WriteBatchAndWaitAsync(IDictionary<string, object?> values, string flagPath, object? flagValue, string responsePath, object? responseValue, TimeSpan timeout, CancellationToken cancellationToken = default);
    ConnectionHealth Status { get; }

    /// <summary>
    /// Raised when the adapter detects an unexpected connection loss (e.g., gRPC stream error,
    /// network timeout). The DataConnectionActor listens for this to trigger reconnection
    /// and push bad quality to all subscribed tags.
    /// </summary>
    event Action? Disconnected;
}
