namespace GestionaDenunciasAN.Services;

public sealed class UiBusyService
{
    private readonly object _syncRoot = new();
    private long _scopeCounter;
    private long _activeScope;

    public event Action? Changed;

    public bool IsVisible { get; private set; }
    public string Title { get; private set; } = string.Empty;
    public string Message { get; private set; } = string.Empty;
    public string? Detail { get; private set; }
    public int? Current { get; private set; }
    public int? Total { get; private set; }

    public bool IsIndeterminate => Total is not > 0 || Current is null;

    public int ProgressPercent
    {
        get
        {
            if (Total is not > 0 || Current is null)
            {
                return 0;
            }

            return Math.Clamp((int)Math.Round(Current.Value * 100d / Total.Value), 0, 100);
        }
    }

    public IDisposable Show(string title, string message, int? total = null, string? detail = null)
    {
        var scopeId = Interlocked.Increment(ref _scopeCounter);

        lock (_syncRoot)
        {
            _activeScope = scopeId;
            IsVisible = true;
            Title = title;
            Message = message;
            Detail = detail;
            Total = total;
            Current = total is > 0 ? 0 : null;
        }

        NotifyChanged();
        return new BusyScope(this, scopeId);
    }

    public void Update(
        string? title = null,
        string? message = null,
        string? detail = null,
        int? current = null,
        int? total = null)
    {
        lock (_syncRoot)
        {
            if (!IsVisible)
            {
                return;
            }

            if (title is not null)
            {
                Title = title;
            }

            if (message is not null)
            {
                Message = message;
            }

            if (detail is not null)
            {
                Detail = detail;
            }

            if (total is not null)
            {
                Total = total;
            }

            if (current is not null)
            {
                Current = current;
            }
        }

        NotifyChanged();
    }

    public void Hide()
    {
        Hide(null);
    }

    private void Hide(long? scopeId)
    {
        lock (_syncRoot)
        {
            if (scopeId is not null && scopeId.Value != _activeScope)
            {
                return;
            }

            IsVisible = false;
            Title = string.Empty;
            Message = string.Empty;
            Detail = null;
            Current = null;
            Total = null;
        }

        NotifyChanged();
    }

    private void NotifyChanged()
    {
        Changed?.Invoke();
    }

    private sealed class BusyScope(UiBusyService owner, long scopeId) : IDisposable
    {
        private bool _disposed;

        public void Dispose()
        {
            if (_disposed)
            {
                return;
            }

            _disposed = true;
            owner.Hide(scopeId);
        }
    }
}
