using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.Extensions.Logging;
using SharepointToolbox.Core.Messages;
using SharepointToolbox.Core.Models;
using SharepointToolbox.Localization;

namespace SharepointToolbox.ViewModels;

public abstract partial class FeatureViewModelBase : ObservableRecipient
{
    private CancellationTokenSource? _cts;
    private readonly ILogger<FeatureViewModelBase> _logger;

    [ObservableProperty]
    [NotifyCanExecuteChangedFor(nameof(CancelCommand))]
    private bool _isRunning;

    [ObservableProperty]
    private string _statusMessage = string.Empty;

    [ObservableProperty]
    private int _progressValue;

    public IAsyncRelayCommand RunCommand { get; }
    public RelayCommand CancelCommand { get; }

    protected FeatureViewModelBase(ILogger<FeatureViewModelBase> logger)
    {
        _logger = logger;
        RunCommand = new AsyncRelayCommand(ExecuteAsync, () => !IsRunning);
        CancelCommand = new RelayCommand(() => _cts?.Cancel(), () => IsRunning);
        IsActive = true; // Activates ObservableRecipient for WeakReferenceMessenger
    }

    private async Task ExecuteAsync()
    {
        _cts = new CancellationTokenSource();
        IsRunning = true;
        StatusMessage = string.Empty;
        ProgressValue = 0;
        try
        {
            var progress = new Progress<OperationProgress>(p =>
            {
                ProgressValue = p.Total > 0 ? (int)(100.0 * p.Current / p.Total) : 0;
                StatusMessage = p.Message;
                WeakReferenceMessenger.Default.Send(new ProgressUpdatedMessage(p));
            });
            await RunOperationAsync(_cts.Token, progress);
        }
        catch (OperationCanceledException)
        {
            StatusMessage = TranslationSource.Instance["status.cancelled"];
            _logger.LogInformation("Operation cancelled by user.");
        }
        catch (Exception ex)
        {
            StatusMessage = $"{TranslationSource.Instance["err.generic"]} {ex.Message}";
            _logger.LogError(ex, "Operation failed.");
        }
        finally
        {
            IsRunning = false;
            _cts?.Dispose();
            _cts = null;
        }
    }

    protected abstract Task RunOperationAsync(CancellationToken ct, IProgress<OperationProgress> progress);

    protected override void OnActivated()
    {
        Messenger.Register<TenantSwitchedMessage>(this, (r, m) => ((FeatureViewModelBase)r).OnTenantSwitched(m.Value));
    }

    protected virtual void OnTenantSwitched(TenantProfile profile)
    {
        // Derived classes override to reset their state
    }
}
