using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using NexusShell.Agent;
using NexusShell.Models;
using NexusShell.Services.Identity;

namespace NexusShell.ViewModels;

public sealed class NexusEnrollmentViewModel : INotifyPropertyChanged
{
    private readonly NexusIdentityService _identity;
    private readonly NexusEnrollmentService _enrollment;
    private readonly NexusAgentConfig _agentConfig;
    private readonly string _shellVersion;

    private NexusOrganizationOption? _selectedOrganization;
    private string _userName = string.Empty;
    private string _deviceFriendlyName = string.Empty;
    private string? _errorMessage;
    private bool _isBusy;

    public NexusEnrollmentViewModel(
        NexusIdentityService identity,
        NexusAgentConfig agentConfig,
        string shellVersion)
    {
        _identity = identity;
        _enrollment = identity.Enrollment;
        _agentConfig = agentConfig;
        _shellVersion = shellVersion;

        _deviceFriendlyName = Environment.MachineName;
        Organizations = new ObservableCollection<NexusOrganizationOption>(NexusOrganizationCatalog.All);

        EnrollCommand = new RelayCommand(async _ => await EnrollAsync(), _ => CanSubmit);
    }

    public event PropertyChangedEventHandler? PropertyChanged;
    public event EventHandler? EnrollmentCompleted;

    public ObservableCollection<NexusOrganizationOption> Organizations { get; }

    public NexusOrganizationOption? SelectedOrganization
    {
        get => _selectedOrganization;
        set { _selectedOrganization = value; OnPropertyChanged(); OnPropertyChanged(nameof(CanSubmit)); }
    }

    public string UserName
    {
        get => _userName;
        set { _userName = value; OnPropertyChanged(); OnPropertyChanged(nameof(CanSubmit)); }
    }

    public string DeviceFriendlyName
    {
        get => _deviceFriendlyName;
        set { _deviceFriendlyName = value; OnPropertyChanged(); OnPropertyChanged(nameof(CanSubmit)); }
    }

    public string? ErrorMessage
    {
        get => _errorMessage;
        private set { _errorMessage = value; OnPropertyChanged(); }
    }

    public bool IsBusy
    {
        get => _isBusy;
        private set
        {
            _isBusy = value;
            OnPropertyChanged();
            OnPropertyChanged(nameof(IsNotBusy));
            OnPropertyChanged(nameof(CanSubmit));
        }
    }

    public bool IsNotBusy => !IsBusy;

    public bool CanSubmit =>
        !IsBusy &&
        SelectedOrganization is not null &&
        !string.IsNullOrWhiteSpace(UserName) &&
        !string.IsNullOrWhiteSpace(DeviceFriendlyName);

    public ICommand EnrollCommand { get; }

    private async Task EnrollAsync()
    {
        if (SelectedOrganization is null)
        {
            ErrorMessage = "Vælg organisation.";
            return;
        }

        IsBusy = true;
        ErrorMessage = null;

        try
        {
            await Task.Yield();

            var result = _enrollment.Enroll(
                new NexusEnrollmentRequest
                {
                    OrganizationId = SelectedOrganization.Id,
                    UserName = UserName,
                    DeviceFriendlyName = DeviceFriendlyName,
                },
                _shellVersion,
                NexusAgentConfig.AgentVersion);

            if (!result.Success)
            {
                ErrorMessage = result.Error;
                return;
            }

            _enrollment.SyncAgentConfig(_agentConfig);
            _identity.LoadAll();
            EnrollmentCompleted?.Invoke(this, EventArgs.Empty);
        }
        catch (Exception ex)
        {
            ErrorMessage = ex.Message;
        }
        finally
        {
            IsBusy = false;
        }
    }

    private void OnPropertyChanged([CallerMemberName] string? name = null) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
