using System.Windows;
using System.Windows.Threading;
using PSLauncher.Core.Localization;

namespace PSLauncher.App.Views;

/// <summary>
/// Modal de lancement automatique de PROSERVE. Utilisé pour les 3 entry points
/// du mode auto :
///   1. Click sur le bouton AUTO d'une row → désigne + lance
///   2. Démarrage du launcher avec mode auto configuré → lance
///   3. PROSERVE quitte alors qu'il était la version auto → relance
///
/// Deux phases possibles selon <see cref="AutoModeConfig.WaitForHealthChecks"/> :
///   • <b>Phase santé</b> (optionnelle) : si la config dit d'attendre que tous
///     les indicateurs de santé système soient OK, on poll le callback
///     <see cref="_healthSnapshot"/> tant qu'il retourne une liste non vide.
///     Le bouton Annuler permet de sortir et désactiver le mode auto.
///   • <b>Phase countdown</b> : décompte visuel de N secondes avant lancement
///     (configurable via GracePeriodSeconds, clampé 1-60).
///
/// DialogResult :
///   <c>true</c>  = phase countdown terminée à zéro, MainViewModel doit lancer
///   <c>false</c> = l'opérateur a cliqué Annuler (à n'importe quelle phase),
///                  MainViewModel doit désactiver SelectedVersion
/// </summary>
public partial class AutoRelaunchDialog : Window
{
    private readonly DispatcherTimer _timer;
    private readonly int _graceSeconds;
    private readonly string _versionName;

    /// <summary>
    /// Callback fourni par MainViewModel pour interroger l'état de santé.
    /// Retourne la liste des NOMS d'indicateurs qui ne sont PAS encore OK
    /// (Warning, Error, ou Unknown). Liste vide ⇒ tout est OK ⇒ on peut
    /// passer à la phase countdown. Null si la phase santé n'est pas
    /// demandée pour ce lancement (option WaitForHealthChecks=false ou
    /// aucun health check configuré).
    /// </summary>
    private readonly Func<IReadOnlyList<string>>? _healthSnapshot;

    private enum Phase { HealthWait, Countdown }
    private Phase _phase;
    private int _remainingSeconds;

    public AutoRelaunchDialog(string versionName, int graceSeconds,
        Func<IReadOnlyList<string>>? healthSnapshot = null)
    {
        InitializeComponent();
        _versionName = versionName;
        _graceSeconds = Math.Clamp(graceSeconds, 1, 60);
        _remainingSeconds = _graceSeconds;
        _healthSnapshot = healthSnapshot;

        // Si on a un callback santé ET qu'au premier check il y a des
        // indicateurs en attente, on démarre en phase santé. Sinon on saute
        // direct au countdown (cas WaitForHealthChecks=false OU tout est
        // déjà OK au moment où le dialog s'ouvre).
        var initialPending = _healthSnapshot?.Invoke() ?? Array.Empty<string>();
        if (initialPending.Count > 0)
        {
            _phase = Phase.HealthWait;
            EnterHealthWaitPhase(initialPending);
        }
        else
        {
            _phase = Phase.Countdown;
            EnterCountdownPhase();
        }

        // Un seul timer pour les deux phases : poll santé toutes les 1s ou
        // décrémente le countdown toutes les 1s. Simplifie le cleanup.
        _timer = new DispatcherTimer(DispatcherPriority.Normal)
        {
            Interval = TimeSpan.FromSeconds(1),
        };
        _timer.Tick += OnTick;
        _timer.Start();
    }

    private void EnterHealthWaitPhase(IReadOnlyList<string> pending)
    {
        TitleText.Text = Strings.AutoLaunchHealthWaitTitle;
        MessageText.Text = Strings.AutoLaunchHealthWaitMessage;
        HealthPendingText.Visibility = Visibility.Visible;
        CountdownText.Visibility = Visibility.Collapsed;
        UpdatePendingText(pending);
    }

    private void EnterCountdownPhase()
    {
        TitleText.Text = Strings.AutoRelaunchTitle;
        MessageText.Text = Strings.AutoRelaunchMessage(_versionName);
        HealthPendingText.Visibility = Visibility.Collapsed;
        CountdownText.Visibility = Visibility.Visible;
        _remainingSeconds = _graceSeconds;
        UpdateCountdown();
    }

    private void UpdatePendingText(IReadOnlyList<string> pending)
    {
        // Ligne 1 : "Indicateurs en attente : N". Ligne 2 : noms séparés par ' • '.
        // On limite à 4 noms affichés pour ne pas casser le layout si l'opérateur
        // a configuré 15 checks. Le tooltip système couvre le détail complet.
        var header = Strings.AutoLaunchHealthWaitPending(pending.Count);
        var preview = pending.Count <= 4
            ? string.Join("  •  ", pending)
            : string.Join("  •  ", pending.Take(4)) + "  …";
        HealthPendingText.Text = $"{header}\n{preview}";
    }

    private void OnTick(object? sender, EventArgs e)
    {
        if (_phase == Phase.HealthWait)
        {
            var pending = _healthSnapshot?.Invoke() ?? Array.Empty<string>();
            if (pending.Count == 0)
            {
                // Transition vers countdown : tout est OK maintenant.
                _phase = Phase.Countdown;
                EnterCountdownPhase();
            }
            else
            {
                UpdatePendingText(pending);
            }
            return;
        }

        // Phase.Countdown
        _remainingSeconds--;
        if (_remainingSeconds <= 0)
        {
            _timer.Stop();
            DialogResult = true; // lancement
            Close();
        }
        else
        {
            UpdateCountdown();
        }
    }

    private void UpdateCountdown()
    {
        CountdownText.Text = _remainingSeconds.ToString();
    }

    private void OnCancel(object sender, RoutedEventArgs e)
    {
        _timer.Stop();
        DialogResult = false; // annulation
        Close();
    }

    protected override void OnClosed(EventArgs e)
    {
        _timer.Stop();
        base.OnClosed(e);
    }
}
