using Microsoft.AspNetCore.SignalR.Client;

namespace RobotNet.Clients;

public abstract class HubClient
{
    public event Action<HubConnectionState>? ConnectionStateChanged;
    public bool IsConnected => Connection.State == HubConnectionState.Connected;
    protected HubConnection Connection { get; }

    protected HubClient(Uri url, Func<Task<string?>> accessTokenProvider)
    {
        Connection = new HubConnectionBuilder()
                            .WithUrl(url, options =>
                            {
                                options.AccessTokenProvider = accessTokenProvider;
                            })
                            .WithAutomaticReconnect(new HubClientRepeatRetryPolicy(TimeSpan.FromSeconds(3)))
                            .Build();

        Connection.Closed += Connection_Closed;
        Connection.Reconnected += Connection_Reconnected;
    }

    private Task Connection_Closed(Exception? arg)
    {
        ConnectionStateChanged?.Invoke(Connection.State);
        return Task.CompletedTask;
    }
    private Task Connection_Reconnected(string? arg)
    {
        ConnectionStateChanged?.Invoke(Connection.State);
        return Task.CompletedTask;
    }

    public virtual async Task StartAsync()
    {
        if (Connection.State == HubConnectionState.Disconnected)
        {
            await Connection.StartAsync();
            ConnectionStateChanged?.Invoke(Connection.State);
        }
    }

    public virtual async Task StopAsync()
    {
        if (Connection.State != HubConnectionState.Disconnected)
        {
            await Connection.StopAsync();
            ConnectionStateChanged?.Invoke(Connection.State);
        }
    }

    public class HubClientRepeatRetryPolicy(TimeSpan repeatSpan) : IRetryPolicy
    {
        private readonly TimeSpan RepeatTimeSpan = repeatSpan;

        public TimeSpan? NextRetryDelay(RetryContext retryContext) => RepeatTimeSpan;
    }
}
