@using SilverOS.Welcome.Core.Apps
@using SilverOS.Welcome.Core.Preconfig
@inject IApplyService ApplyService
@inject IAppCatalog AppCatalog
@inject IPreconfigStore PreconfigStore
@inject WizardState State

<div class="step apply-step">
    <div class="apply-header">
        <h1>Applying Configuration</h1>
        <p class="step-subtitle">Your SilverOS is being configured. This may take a few minutes.</p>
    </div>

    @if (_errorMessage is not null)
    {
        <div class="apply-error">
            <div class="apply-error-icon">&#x26A0;</div>
            <p class="apply-error-title">Configuration failed</p>
            <p class="apply-error-detail">@SanitiseForDisplay(_errorMessage)</p>
            <button class="btn-primary btn-retry" @onclick="() => _ = StartAsync()">Retry</button>
        </div>
    }
    else if (!_running && !_complete)
    {
        <div class="apply-ready">
            <p class="apply-ready-text">Ready to apply your selections. Click Start to begin.</p>
            <button class="btn-primary btn-start" @onclick="() => _ = StartAsync()" disabled="@_running">Start</button>
        </div>
    }
    else
    {
        <div class="apply-progress-container">
            <div class="apply-stage-label">@_stageLabel</div>
            <div class="apply-progress-track">
                <div class="apply-progress-bar" style="width: @(_percent)%"></div>
            </div>
            <div class="apply-percent-label">@(_percent)%</div>
        </div>

        @if (_complete)
        {
            <div class="apply-complete">
                <div class="apply-complete-icon">&#x2713;</div>
                <p>Configuration complete.</p>
            </div>
        }
    }
</div>

@code {
    [Parameter] public EventCallback OnComplete { get; set; }
    [Parameter] public EventCallback<bool> OnRunningChanged { get; set; }
    [Parameter] public bool AutoStart { get; set; }

    private bool _running;
    private bool _autoStarted;
    private bool _complete;
    private int _percent;
    private string _stageLabel = "Preparing…";
    private string? _errorMessage;

    private const int ErrorDisplayMaxLength = 200;

    /// <summary>
    /// Strips newlines and caps length so a multi-line or huge error message
    /// cannot dump raw output into the UI.
    /// </summary>
    private static string SanitiseForDisplay(string message)
    {
        var single = message.ReplaceLineEndings(" ").Trim();
        return single.Length <= ErrorDisplayMaxLength
            ? single
            : single[..ErrorDisplayMaxLength] + "…";
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        // First-run auto-apply: when the host jumps straight to this step with AutoStart,
        // kick off the same apply the Start button would, exactly once. The manual path
        // (AutoStart=false) is untouched.
        if (firstRender && AutoStart && !_autoStarted)
        {
            _autoStarted = true;
            await StartAsync();
        }
    }

    public async Task StartAsync()
    {
        // Re-entrancy guard: prevent a second overlapping apply if already running
        // (e.g. rapid double-click on Retry).
        if (_running) return;

        _running = true;
        _complete = false;
        _errorMessage = null;
        _percent = 0;
        _stageLabel = "Preparing…";
        StateHasChanged();
        await OnRunningChanged.InvokeAsync(true);

        var apps = AppCatalog.Load(Path.Combine(AppContext.BaseDirectory, "apps"))
                             .All.Where(a => State.SelectedApps.Contains(a.Id)).ToList();

        // D1: Apply is now apps+bitlocker only (account via Setup, hardening via SetupComplete).
        // D2 owns the full UI rewire (run-mode / preseed); this passes the 3-arg request from
        // existing State fields so the app keeps compiling.
        var req = new ApplyRequest(
            Flavour: State.Flavour!,
            BitLockerPin: State.BitLockerPin,
            Apps: apps);

        var progress = new Progress<ApplyProgress>(p =>
        {
            _ = InvokeAsync(() =>
            {
                _percent = p.Percent;
                _stageLabel = p.Stage;
                StateHasChanged();
            });
        });

        try
        {
            await ApplyService.RunAsync(req, progress);
            _complete = true;
            _running = false;
            _percent = 100;

            // Apply succeeded: wipe the BitLocker pin from the preconfig and stamp the
            // configured marker so the next launch opens toolbox-home instead of re-applying.
            PreconfigStore.ClearPin();
            PreconfigStore.MarkConfigured();

            StateHasChanged();
            await OnRunningChanged.InvokeAsync(false);
            await OnComplete.InvokeAsync();
        }
        catch (Exception ex)
        {
            _running = false;
            _errorMessage = ex.Message;
            StateHasChanged();
            await OnRunningChanged.InvokeAsync(false);
        }
    }
}
