using System;
using System.Windows;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using HC_APTBS.Services;
namespace HC_APTBS.ViewModels.Dialogs
{
///
/// ViewModel for the Dashboard "Connect & Auto Test" snackbar.
/// Receives transitions and failure reasons from the
/// orchestrator, exposes snackbar-friendly bindings (progress, phase text, success),
/// and forwards the Cancel click to the orchestrator's CTS.
/// Modelled on .
///
public sealed partial class AutoTestProgressViewModel : ObservableObject, IDisposable
{
private readonly IAutoTestOrchestrator _orchestrator;
private readonly ILocalizationService _loc;
/// Creates the ViewModel and subscribes to orchestrator events.
public AutoTestProgressViewModel(IAutoTestOrchestrator orchestrator, ILocalizationService loc)
{
_orchestrator = orchestrator;
_loc = loc;
_typeLabel = _loc.GetString("AutoTest.TypeLabel");
_phaseText = _loc.GetString("AutoTest.State.Preflight");
_isCancellable = true;
_orchestrator.StateChanged += OnStateChanged;
_orchestrator.Failed += OnFailed;
}
// ── Observable properties ────────────────────────────────────────────────
/// Progress percentage (0–100). Meaningful during Unlocking and test Running phases.
[ObservableProperty] private int _progress;
/// Leading label (localised "Auto Test").
[ObservableProperty] private string _typeLabel;
/// Current phase description shown in the snackbar.
[ObservableProperty] private string _phaseText;
/// Terminal result text — populated on Completed/Aborted.
[ObservableProperty] private string _resultText = string.Empty;
/// True once the sequence reaches Completed or Aborted.
[NotifyCanExecuteChangedFor(nameof(CloseCommand))]
[ObservableProperty] private bool _isComplete;
/// True while the Cancel button should be enabled (all non-terminal states).
[NotifyCanExecuteChangedFor(nameof(CancelCommand))]
[ObservableProperty] private bool _isCancellable;
/// Tri-state: null while running, true = success, false = failure.
[ObservableProperty] private bool? _isSuccess;
// ── Commands ─────────────────────────────────────────────────────────────
/// Cancels the orchestrator's current sequence.
[RelayCommand(CanExecute = nameof(IsCancellable))]
private void Cancel() => _orchestrator.Cancel();
/// Closes the snackbar (emits ).
[RelayCommand(CanExecute = nameof(IsComplete))]
private void Close() => RequestClose?.Invoke();
// ── Events ───────────────────────────────────────────────────────────────
/// Raised when the snackbar should close itself (after success / user dismiss).
public event Action? RequestClose;
// ── Orchestrator event handlers ──────────────────────────────────────────
private void OnStateChanged(AutoTestState state, string? detail)
{
Application.Current?.Dispatcher?.Invoke(() =>
{
switch (state)
{
case AutoTestState.Preflight:
PhaseText = _loc.GetString("AutoTest.State.Preflight");
break;
case AutoTestState.ConnectingKLine:
PhaseText = _loc.GetString("AutoTest.State.Connecting");
break;
case AutoTestState.ReadingPump:
PhaseText = _loc.GetString("AutoTest.State.Reading");
if (!string.IsNullOrEmpty(detail) && int.TryParse(detail, out int pct))
Progress = pct;
break;
case AutoTestState.Unlocking:
PhaseText = string.IsNullOrEmpty(detail)
? _loc.GetString("AutoTest.State.Unlocking")
: string.Format(_loc.GetString("AutoTest.State.UnlockingWithDetail"), detail);
break;
case AutoTestState.TurningOnBench:
PhaseText = _loc.GetString("AutoTest.State.BenchOn");
break;
case AutoTestState.StartingOilPump:
PhaseText = _loc.GetString("AutoTest.State.OilPump");
break;
case AutoTestState.StartingTest:
PhaseText = _loc.GetString("AutoTest.State.TestStart");
break;
case AutoTestState.Running:
PhaseText = string.IsNullOrEmpty(detail)
? _loc.GetString("AutoTest.State.Running")
: string.Format(_loc.GetString("AutoTest.State.RunningWithPhase"), detail);
break;
case AutoTestState.Completed:
PhaseText = _loc.GetString("AutoTest.State.Completed");
ResultText = PhaseText;
Progress = 100;
IsComplete = true;
IsCancellable = false;
IsSuccess = true;
break;
case AutoTestState.Aborted:
// Detail populated by OnFailed; still terminal.
IsComplete = true;
IsCancellable = false;
IsSuccess = false;
break;
}
});
}
private void OnFailed(AutoTestFailureReason reason, string message)
{
Application.Current?.Dispatcher?.Invoke(() =>
{
string key = "AutoTest.Failure." + reason;
string localised = _loc.GetString(key);
if (string.IsNullOrEmpty(localised) || localised == key)
localised = reason.ToString();
ResultText = string.IsNullOrEmpty(message)
? localised
: $"{localised}: {message}";
PhaseText = string.Format(_loc.GetString("AutoTest.State.Aborted"), ResultText);
IsComplete = true;
IsCancellable = false;
IsSuccess = false;
});
}
// ── IDisposable ──────────────────────────────────────────────────────────
/// Unsubscribes from orchestrator events.
public void Dispose()
{
_orchestrator.StateChanged -= OnStateChanged;
_orchestrator.Failed -= OnFailed;
}
}
}