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

namespace NexusShell.ViewModels;

public sealed class NexusSetupFlowViewModel : INotifyPropertyChanged
{
    private static readonly TimeSpan EnrollmentTimeout = TimeSpan.FromSeconds(30);

    private readonly NexusIdentityService _identity;
    private readonly NexusEnrollmentService _enrollment;
    private readonly NexusPlatformLockService _platformLock;
    private readonly NexusAgentConfig _agentConfig;
    private readonly string _shellVersion;

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

    public NexusSetupFlowViewModel(
        NexusIdentityService identity,
        NexusPlatformLockService platformLock,
        NexusAgentConfig agentConfig,
        string shellVersion)
    {
        _identity = identity;
        _enrollment = identity.Enrollment;
        _platformLock = platformLock;
        _agentConfig = agentConfig;
        _shellVersion = shellVersion;
        _deviceFriendlyName = Environment.MachineName;

        Organizations = new ObservableCollection<NexusOrganizationOption>(NexusOrganizationCatalog.All);
        SelectedOrganization = Organizations.Count == 1
            ? Organizations[0]
            : Organizations.FirstOrDefault();

        NextCommand = new RelayCommand(_ => GoNext(), _ => CanGoNext && !IsBusy);
        BackCommand = new RelayCommand(_ => GoBack(), _ => CanGoBack && !IsBusy);
        CancelCommand = new RelayCommand(_ => CancelRequested?.Invoke(this, EventArgs.Empty));
    }

    public event PropertyChangedEventHandler? PropertyChanged;
    public event EventHandler? SetupCompleted;
    public event EventHandler? CancelRequested;

    public ObservableCollection<NexusOrganizationOption> Organizations { get; }

    public int CurrentStepNumber => (int)_currentStep;

    public string StepProgressLabel => $"Trin {CurrentStepNumber} af 5";

    public string StepTitle => _currentStep switch
    {
        NexusSetupStep.Welcome => "Velkommen til Nexus Platform",
        NexusSetupStep.Organization => "Vælg organisation",
        NexusSetupStep.User => "Hvem bruger denne enhed?",
        NexusSetupStep.Device => "Navngiv enheden",
        NexusSetupStep.Security => "Sikkerhed og færdiggørelse",
        _ => string.Empty,
    };

    public string StepDescription => _currentStep switch
    {
        NexusSetupStep.Welcome =>
            "Denne guide registrerer enheden i Nexus Identity og forbereder platformen. Windows låses efter installation — kun Nexus og godkendte apps er tilgængelige.",
        NexusSetupStep.Organization =>
            "Vælg hvilken organisation denne enhed tilhører.",
        NexusSetupStep.User =>
            "Angiv navnet på den primære bruger af enheden.",
        NexusSetupStep.Device =>
            "Giv enheden et genkendeligt navn. Device ID genereres automatisk ved færdiggørelse.",
        NexusSetupStep.Security =>
            "Nexus låser Windows taskbar og skrivebord efter installation. POC: Admins kan midlertidigt låse Windows op med Ctrl+Shift+Alt+U.",
        _ => string.Empty,
    };

    public bool IsWelcomeStep => _currentStep == NexusSetupStep.Welcome;
    public bool IsOrganizationStep => _currentStep == NexusSetupStep.Organization;
    public bool IsUserStep => _currentStep == NexusSetupStep.User;
    public bool IsDeviceStep => _currentStep == NexusSetupStep.Device;
    public bool IsSecurityStep => _currentStep == NexusSetupStep.Security;

    public bool IsStepActive1 => CurrentStepNumber >= 1;
    public bool IsStepActive2 => CurrentStepNumber >= 2;
    public bool IsStepActive3 => CurrentStepNumber >= 3;
    public bool IsStepActive4 => CurrentStepNumber >= 4;
    public bool IsStepActive5 => CurrentStepNumber >= 5;

    public bool AreInputsEnabled => !IsBusy;

    public bool IsOrganizationListEmpty => Organizations.Count == 0;

    public bool ShowOrganizationStatus => Organizations.Count == 0 || SelectedOrganization is null;

    public string OrganizationStatusMessage => Organizations.Count switch
    {
        0 => "Ingen organisationer tilgængelige. Kontroller netværk og prøv igen.",
        _ when SelectedOrganization is null => "Vælg organisation i listen.",
        _ => string.Empty,
    };

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

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

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

    public string ComputerName => Environment.MachineName;

    public string SummaryOrganization => SelectedOrganization?.Name ?? "—";
    public string SummaryUser => string.IsNullOrWhiteSpace(UserName) ? "—" : UserName.Trim();
    public string SummaryDevice => string.IsNullOrWhiteSpace(DeviceFriendlyName) ? "—" : DeviceFriendlyName.Trim();

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

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

    public bool CanGoBack => _currentStep > NexusSetupStep.Welcome;

    public bool CanGoNext => _currentStep switch
    {
        NexusSetupStep.Welcome => true,
        NexusSetupStep.Organization => SelectedOrganization is not null,
        NexusSetupStep.User => !string.IsNullOrWhiteSpace(UserName),
        NexusSetupStep.Device => !string.IsNullOrWhiteSpace(DeviceFriendlyName),
        NexusSetupStep.Security => SelectedOrganization is not null &&
                                     !string.IsNullOrWhiteSpace(UserName) &&
                                     !string.IsNullOrWhiteSpace(DeviceFriendlyName),
        _ => false,
    };

    public string NextButtonLabel =>
        _currentStep == NexusSetupStep.Security ? "Færdiggør installation" : "Næste";

    public ICommand NextCommand { get; }
    public ICommand BackCommand { get; }
    public ICommand CancelCommand { get; }

    private void GoBack()
    {
        if (!CanGoBack)
        {
            return;
        }

        _currentStep = (NexusSetupStep)((int)_currentStep - 1);
        ErrorMessage = null;
        NotifyStepChanged();
    }

    private async void GoNext()
    {
        if (!CanGoNext || IsBusy)
        {
            return;
        }

        if (_currentStep == NexusSetupStep.Security)
        {
            await CompleteSetupAsync();
            return;
        }

        _currentStep = (NexusSetupStep)((int)_currentStep + 1);
        EnsureOrganizationSelectedForStep();
        ErrorMessage = null;
        NotifyStepChanged();
    }

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

        IsBusy = true;
        ErrorMessage = null;

        try
        {
            using var timeoutCts = new CancellationTokenSource(EnrollmentTimeout);
            var enrollTask = Task.Run(() =>
            {
                timeoutCts.Token.ThrowIfCancellationRequested();
                return _enrollment.Enroll(
                    new NexusEnrollmentRequest
                    {
                        OrganizationId = SelectedOrganization.Id,
                        UserName = UserName,
                        DeviceFriendlyName = DeviceFriendlyName,
                    },
                    _shellVersion,
                    NexusAgentConfig.AgentVersion);
            }, timeoutCts.Token);

            var result = await enrollTask.ConfigureAwait(true);

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

            _enrollment.SyncAgentConfig(_agentConfig);
            _identity.LoadAll();
            _platformLock.EnableAfterEnrollment(UserName.Trim());
            SetupCompleted?.Invoke(this, EventArgs.Empty);
        }
        catch (OperationCanceledException)
        {
            ErrorMessage = "Registrering tog for lang tid. Prøv igen.";
        }
        catch (Exception ex)
        {
            ErrorMessage = ex.Message;
        }
        finally
        {
            IsBusy = false;
        }
    }

    private void NotifyStepChanged()
    {
        OnPropertyChanged(nameof(CurrentStepNumber));
        OnPropertyChanged(nameof(StepProgressLabel));
        OnPropertyChanged(nameof(StepTitle));
        OnPropertyChanged(nameof(StepDescription));
        OnPropertyChanged(nameof(IsWelcomeStep));
        OnPropertyChanged(nameof(IsOrganizationStep));
        OnPropertyChanged(nameof(IsUserStep));
        OnPropertyChanged(nameof(IsDeviceStep));
        OnPropertyChanged(nameof(IsSecurityStep));
        OnPropertyChanged(nameof(IsStepActive1));
        OnPropertyChanged(nameof(IsStepActive2));
        OnPropertyChanged(nameof(IsStepActive3));
        OnPropertyChanged(nameof(IsStepActive4));
        OnPropertyChanged(nameof(IsStepActive5));
        OnPropertyChanged(nameof(SummaryOrganization));
        OnPropertyChanged(nameof(SummaryUser));
        OnPropertyChanged(nameof(SummaryDevice));
        NotifyNavigation();
    }

    private void EnsureOrganizationSelectedForStep()
    {
        if (_currentStep != NexusSetupStep.Organization || SelectedOrganization is not null)
        {
            return;
        }

        SelectedOrganization = Organizations.FirstOrDefault();
    }

    private void NotifyNavigation()
    {
        OnPropertyChanged(nameof(CanGoBack));
        OnPropertyChanged(nameof(CanGoNext));
        OnPropertyChanged(nameof(NextButtonLabel));
        CommandManager.InvalidateRequerySuggested();
    }

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