using System.ComponentModel;
using System.Linq;
using System.Windows;
using ClaudeDo.Installer.Core;
using ClaudeDo.Installer.Pages.InstallPage;
using ClaudeDo.Installer.Pages.WelcomePage;
using ClaudeDo.Localization;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;

namespace ClaudeDo.Installer.Views;

public partial class WizardViewModel : ObservableObject
{
    private readonly InstallContext _context;
    private readonly ILocalizer _localizer;

    public IReadOnlyList<IInstallerPage> Pages { get; }
    public IReadOnlyList<LanguageOption> Languages { get; }

    [ObservableProperty]
    private LanguageOption? _selectedLanguage;

    partial void OnSelectedLanguageChanged(LanguageOption? value)
    {
        if (value is null) return;
        _localizer.SetLanguage(value.Value.Code);
        _context.Language = value.Value.Code;
    }

    [ObservableProperty]
    [NotifyPropertyChangedFor(nameof(CanGoBack))]
    [NotifyPropertyChangedFor(nameof(IsLastPage))]
    [NotifyPropertyChangedFor(nameof(NextButtonText))]
    [NotifyPropertyChangedFor(nameof(CurrentPage))]
    [NotifyPropertyChangedFor(nameof(CanGoNext))]
    private int _currentPageIndex;

    public IInstallerPage CurrentPage => Pages[CurrentPageIndex];
    public bool CanGoBack => CurrentPageIndex > 0;
    public bool CanGoNext => !CurrentPage.BlocksNavigation;
    public bool IsLastPage => CurrentPageIndex == Pages.Count - 1;
    public string NextButtonText => IsLastPage
        ? (_localizer["installer.nav.install"])
        : (_localizer["installer.nav.next"]);

    [ObservableProperty]
    private string? _validationError;

    public WizardViewModel(PageResolver resolver, InstallContext context, ILocalizer localizer)
    {
        _context = context;
        _localizer = localizer;
        Languages = localizer.AvailableLanguages;
        _selectedLanguage = Languages.FirstOrDefault(l => l.Code == localizer.CurrentCode);
        _context.Language = localizer.CurrentCode;

        var all = resolver.WizardPages;
        Pages = context.Mode == InstallerMode.Update
            ? all.Where(p => p is WelcomePageViewModel
                          || p is InstallPageViewModel).ToList()
            : all;

        // A page's blocking state (e.g. a running/failed system check) can change while it's
        // displayed; re-evaluate CanGoNext whenever any page raises a property change.
        foreach (var page in Pages)
        {
            if (page is INotifyPropertyChanged notifying)
                notifying.PropertyChanged += (_, _) => OnPropertyChanged(nameof(CanGoNext));
        }

        if (Pages.Count > 0)
            _ = InitAsync();
    }

    private async Task InitAsync()
    {
        try { await Pages[0].LoadAsync(); }
        catch { /* first page loads with defaults on error */ }
    }

    [RelayCommand]
    private async Task GoBack()
    {
        if (!CanGoBack) return;
        CurrentPageIndex--;
        await CurrentPage.LoadAsync();
        ValidationError = null;
    }

    [RelayCommand]
    private async Task GoNext()
    {
        if (!CurrentPage.Validate())
        {
            ValidationError = "Please fix the highlighted errors before continuing.";
            return;
        }

        ValidationError = null;
        await CurrentPage.ApplyAsync();

        if (CurrentPageIndex < Pages.Count - 1)
        {
            CurrentPageIndex++;
            await CurrentPage.LoadAsync();
        }
    }

    [RelayCommand]
    private void Close()
    {
        Application.Current.Shutdown();
    }
}
