using InnovEnergy.Lib.Utils;

namespace InnovEnergy.Lib.Channels;

public abstract class Connection : IAsyncDisposable
{
    private readonly CloseAfter  _CloseAfter;
    private readonly AsyncAction _Open;
    private readonly AsyncAction _Close;

    protected Connection(AsyncAction? open = null, AsyncAction? close = null, CloseAfter closeAfter = CloseAfter.Error)
    {
        _CloseAfter = closeAfter;
        _Open       = open  ?? (() => Task.CompletedTask);
        _Close      = close ?? (() => Task.CompletedTask);
    }
    
    protected Connection(CloseAfter closeAfter = CloseAfter.Error) : this(null, null, closeAfter)
    {}


    protected async Task CloseAfterError()
    {
        if (_CloseAfter.HasFlag(CloseAfter.Error))
            await Close();
    }
    
    protected async Task CloseAfterTransmit()
    {
        if (_CloseAfter.HasFlag(CloseAfter.Transmit))
            await Close();
    }
    
    protected async Task CloseAfterReceive()
    {
        if (_CloseAfter.HasFlag(CloseAfter.Receive))
            await Close();
    }
    
    public async Task Open()
    {
        try
        {
            await _Open();
        }
        catch (Exception)
        {
            if (_CloseAfter.HasFlag(CloseAfter.Error))
                await Close();

            throw;
        }
    }

    public async Task Close()
    {
        try
        {
            await _Close();
        }
        catch
        {
            // ignored
        }
    }

    public async ValueTask DisposeAsync()
    {
        await Close();
        GC.SuppressFinalize(this);
    }
}