using System;
using System.Threading.Tasks;
using System.Windows.Input;

namespace Tornado3_2026Election.Common;

public sealed class AsyncRelayCommand : ObservableObject, ICommand
{
    private readonly Func<Task> _execute;
    private readonly Func<bool>? _canExecute;
    private readonly bool _allowConcurrentExecutions;
    private bool _isRunning;

    public AsyncRelayCommand(
        Func<Task> execute,
        Func<bool>? canExecute = null,
        bool allowConcurrentExecutions = false)
    {
        _execute = execute;
        _canExecute = canExecute;
        _allowConcurrentExecutions = allowConcurrentExecutions;
    }

    public event EventHandler? CanExecuteChanged;

    public bool IsRunning
    {
        get => _isRunning;
        private set
        {
            if (SetProperty(ref _isRunning, value))
            {
                NotifyCanExecuteChanged();
            }
        }
    }

    public bool CanExecute(object? parameter) =>
        (_allowConcurrentExecutions || !IsRunning) &&
        (_canExecute?.Invoke() ?? true);

    public async void Execute(object? parameter)
    {
        if (!CanExecute(parameter))
        {
            return;
        }

        try
        {
            IsRunning = true;
            await _execute();
        }
        finally
        {
            IsRunning = false;
        }
    }

    public void NotifyCanExecuteChanged() => UiDispatcher.Enqueue(() => CanExecuteChanged?.Invoke(this, EventArgs.Empty));
}
