using System.Windows;
using ClaudeDo.Installer.Core;
using ClaudeDo.Localization;
using ClaudeDo.Releases;
using ClaudeDo.Installer.Steps;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;

namespace ClaudeDo.Installer.Views;

public partial class SettingsViewModel : ObservableObject
{
    private readonly InstallContext _context;
    private readonly ILocalizer _localizer;
    private readonly IReleaseClient _releases;
    private readonly StopWorkerStep _stopService;
    private readonly StartWorkerStep _startService;
    private readonly RegisterAutostartStep _registerAutostart;
    private readonly DownloadAndExtractStep _downloadStep;
    private readonly UninstallRunner _uninstallRunner;

    public IReadOnlyList<IInstallerPage> Pages { get; }

    [ObservableProperty]
    private IInstallerPage? _selectedPage;

    [ObservableProperty]
    private string? _statusMessage;

    [ObservableProperty]
    private bool _isStatusError;

    [ObservableProperty]
    private string _versionLabel = "";

    [ObservableProperty]
    private bool _removeAppData;

    public SettingsViewModel(
        PageResolver resolver,
        InstallContext context,
        ILocalizer localizer,
        IReleaseClient releases,
        StopWorkerStep stopService,
        StartWorkerStep startService,
        RegisterAutostartStep registerAutostart,
        DownloadAndExtractStep downloadStep,
        UninstallRunner uninstallRunner)
    {
        Pages = resolver.SettingsPages;
        _context = context;
        _localizer = localizer;
        _releases = releases;
        _stopService = stopService;
        _startService = startService;
        _registerAutostart = registerAutostart;
        _downloadStep = downloadStep;
        _uninstallRunner = uninstallRunner;
        _selectedPage = Pages.FirstOrDefault();

        var label = $"Installed: {context.InstalledVersion ?? "?"}   Installer: {context.InstallerVersion ?? "?"}";
        if (!string.IsNullOrEmpty(context.LatestVersion))
            label += $"   Latest: {context.LatestVersion}";
        if (context.LatestTagUnparseable)
            label += "   (pre-release tag — auto-update disabled)";
        VersionLabel = label;

        _ = LoadAllAsync();
    }

    private async Task LoadAllAsync()
    {
        foreach (var page in Pages)
            await page.LoadAsync();
    }

    [RelayCommand]
    private async Task Save()
    {
        foreach (var page in Pages)
        {
            if (!page.Validate())
            {
                SelectedPage = page;
                StatusMessage = $"Validation failed on {page.Title}. Please fix the errors.";
                IsStatusError = true;
                return;
            }
        }

        foreach (var page in Pages)
            await page.ApplyAsync();

        var workerCfg = new InstallerWorkerConfig
        {
            DbPath = _context.DbPath,
            SandboxRoot = _context.SandboxRoot,
            LogRoot = _context.LogRoot,
            WorktreeRootStrategy = _context.WorktreeRootStrategy,
            CentralWorktreeRoot = _context.CentralWorktreeRoot,
            QueueBackstopIntervalMs = _context.QueueBackstopIntervalMs,
            SignalRPort = _context.SignalRPort,
            ClaudeBin = _context.ClaudeBin,
        };
        workerCfg.Save();

        var uiCfg = new InstallerAppSettings
        {
            DbPath = _context.UiDbPath,
            SignalRUrl = _context.SignalRUrl,
            Language = _localizer.CurrentCode,
        };
        uiCfg.Save();

        IsStatusError = false;
        StatusMessage = "Settings saved.";

        // Worker reads its config at process start, so changes only take effect after a restart.
        var restart = MessageBox.Show(
            "Restart the worker service now so the new settings take effect?",
            "Restart Worker",
            MessageBoxButton.YesNo,
            MessageBoxImage.Question);

        if (restart != MessageBoxResult.Yes)
        {
            StatusMessage = "Settings saved. Restart the worker service manually to apply.";
            return;
        }

        var progress = new Progress<string>(msg => StatusMessage = msg);
        var stop = await _stopService.ExecuteAsync(_context, progress, CancellationToken.None);
        if (!stop.Success)
        {
            StatusMessage = $"Saved, but worker stop failed: {stop.ErrorMessage}";
            IsStatusError = true;
            return;
        }
        var start = await _startService.ExecuteAsync(_context, progress, CancellationToken.None);
        if (!start.Success)
        {
            StatusMessage = $"Saved, but worker start failed: {start.ErrorMessage}";
            IsStatusError = true;
            return;
        }

        StatusMessage = "Settings saved. Worker restarted.";
    }

    [RelayCommand]
    private async Task Repair()
    {
        var confirm = MessageBox.Show(
            "Re-download and reinstall the ClaudeDo binaries? Your config and database are NOT affected.",
            "Repair ClaudeDo",
            MessageBoxButton.OKCancel,
            MessageBoxImage.Question);

        if (confirm != MessageBoxResult.OK) return;

        StatusMessage = "Repairing...";
        IsStatusError = false;

        var progress = new Progress<string>(msg => StatusMessage = msg);
        var steps = new IInstallStep[] { _stopService, _downloadStep, _registerAutostart, _startService };

        foreach (var step in steps)
        {
            var r = await step.ExecuteAsync(_context, progress, CancellationToken.None);
            if (!r.Success)
            {
                StatusMessage = $"{step.Name} failed: {r.ErrorMessage}";
                IsStatusError = true;
                return;
            }
        }

        StatusMessage = "Repair complete.";
    }

    [RelayCommand]
    private async Task Uninstall()
    {
        var dataNote = RemoveAppData
            ? "This will remove ClaudeDo AND delete all of your tasks, configuration, and database.\n\nContinue?"
            : "This will remove ClaudeDo. Your tasks, configuration, and database in ~/.claudeDo will be kept.\n\nContinue?";

        var confirm = MessageBox.Show(
            dataNote,
            "Uninstall ClaudeDo",
            MessageBoxButton.YesNo,
            MessageBoxImage.Warning);

        if (confirm != MessageBoxResult.Yes) return;

        var progress = new Progress<string>(msg => StatusMessage = msg);
        var r = await _uninstallRunner.RunAsync(RemoveAppData, progress, CancellationToken.None);

        if (!r.Success)
        {
            StatusMessage = $"Uninstall failed: {r.ErrorMessage}";
            IsStatusError = true;
            return;
        }

        MessageBox.Show("ClaudeDo has been removed.", "Uninstall complete",
            MessageBoxButton.OK, MessageBoxImage.Information);
        Application.Current.Shutdown();
    }

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