using System.Diagnostics;

namespace RobotNet.RobotManager.Services;

public class WatchTimerAsync<T>(int Interval, Func<Task> Callback, LoggerController<T>? Logger) : IDisposable where T : class
{
    private System.Threading.Timer? Timer;
    private readonly Stopwatch Watch = new();
    public bool Disposed;

    private async void Handler(object? state)
    {
        try
        {
            Watch.Restart();

            await Callback.Invoke();

            Watch.Stop();
            if (Watch.ElapsedMilliseconds >= Interval || Interval - Watch.ElapsedMilliseconds <= 50)
            {
                Timer?.Change(Interval, Timeout.Infinite);
            }
            else
            {
                Timer?.Change(Interval - Watch.ElapsedMilliseconds, Timeout.Infinite);
            }
        }
        catch (Exception ex)
        {
            Logger?.Error($"WatchTimer Error: {ex}");
            Timer?.Change(Interval, Timeout.Infinite);
        }
    }

    public void Start()
    {
        if (!Disposed)
        {
            Timer = new Timer(Handler, null, Timeout.Infinite, Timeout.Infinite);
            Timer.Change(Interval, 0);
        }
        else throw new ObjectDisposedException(nameof(WatchTimerAsync<T>));
    }

    public void Stop()
    {
        if (Disposed) return;
        if (Timer != null)
        {
            Timer.Change(Timeout.Infinite, Timeout.Infinite);
            Timer.Dispose();
            Timer = null;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (Disposed) return;

        if (disposing) Stop();

        Disposed = true;
    }

    ~WatchTimerAsync()
    {
        Dispose(false);
    }
}
