@page "/clusters/{ClusterId}/draft/{GenerationId:long}/import-equipment"
@using Microsoft.AspNetCore.Components.Authorization
@using ZB.MOM.WW.OtOpcUa.Admin.Services
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
@inject DriverInstanceService DriverSvc
@inject UnsService UnsSvc
@inject EquipmentImportBatchService BatchSvc
@inject NavigationManager Nav
@inject AuthenticationStateProvider AuthProvider

<div class="d-flex justify-content-between align-items-center mb-3">
    <div>
        <h1 class="mb-0">Equipment CSV import</h1>
        <small class="text-muted">Cluster <code>@ClusterId</code> · draft generation @GenerationId</small>
    </div>
    <a class="btn btn-outline-secondary" href="/clusters/@ClusterId/draft/@GenerationId">Back to draft</a>
</div>

<div class="alert alert-info small mb-3">
    Accepts <code>@EquipmentCsvImporter.VersionMarker</code>-headered CSV per Stream B.3.
    Required columns: @string.Join(", ", EquipmentCsvImporter.RequiredColumns).
    Optional columns cover the OPC 40010 Identification fields. Paste the file contents
    or upload directly — the parser runs client-stream-side and shows a row-level preview
    before anything lands in the draft. ZTag + SAPID uniqueness across the fleet is NOT
    enforced here yet (see task #197); for now the finalise may fail at commit time if a
    reservation conflict exists.
</div>

<div class="card mb-3">
    <div class="card-body">
        <div class="row g-3">
            <div class="col-md-5">
                <label class="form-label">Target driver instance (for every accepted row)</label>
                <select class="form-select" @bind="_driverInstanceId">
                    <option value="">-- select driver --</option>
                    @if (_drivers is not null)
                    {
                        @foreach (var d in _drivers) { <option value="@d.DriverInstanceId">@d.DriverInstanceId</option> }
                    }
                </select>
            </div>
            <div class="col-md-5">
                <label class="form-label">Target UNS line (for every accepted row)</label>
                <select class="form-select" @bind="_unsLineId">
                    <option value="">-- select line --</option>
                    @if (_unsLines is not null)
                    {
                        @foreach (var l in _unsLines) { <option value="@l.UnsLineId">@l.UnsLineId — @l.Name</option> }
                    }
                </select>
            </div>
            <div class="col-md-2 pt-4">
                <InputFile OnChange="HandleFileAsync" class="form-control form-control-sm" accept=".csv,.txt"/>
            </div>
        </div>
        <div class="mt-3">
            <label class="form-label">CSV content (paste or uploaded)</label>
            <textarea class="form-control font-monospace" rows="8" @bind="_csvText"
                      placeholder="# OtOpcUaCsv v1&#10;ZTag,MachineCode,SAPID,EquipmentId,…"/>
        </div>
        <div class="mt-3">
            <button class="btn btn-sm btn-outline-primary" @onclick="ParseAsync" disabled="@_busy">Parse</button>
            <button class="btn btn-sm btn-primary ms-2" @onclick="StageAndFinaliseAsync"
                    disabled="@(_parseResult is null || _parseResult.AcceptedRows.Count == 0 || string.IsNullOrWhiteSpace(_driverInstanceId) || string.IsNullOrWhiteSpace(_unsLineId) || _busy)">
                Stage + Finalise
            </button>
            @if (_parseError is not null) { <span class="alert alert-danger ms-3 py-1 px-2 small">@_parseError</span> }
            @if (_result is not null) { <span class="alert alert-success ms-3 py-1 px-2 small">@_result</span> }
        </div>
    </div>
</div>

@if (_parseResult is not null)
{
    <div class="row g-3">
        <div class="col-md-6">
            <div class="card">
                <div class="card-header bg-success text-white">
                    Accepted (@_parseResult.AcceptedRows.Count)
                </div>
                <div class="card-body p-0" style="max-height: 400px; overflow-y: auto;">
                    @if (_parseResult.AcceptedRows.Count == 0)
                    {
                        <p class="text-muted p-3 mb-0">No accepted rows.</p>
                    }
                    else
                    {
                        <table class="table table-sm table-striped mb-0">
                            <thead>
                                <tr><th>ZTag</th><th>Machine</th><th>Name</th><th>Line</th></tr>
                            </thead>
                            <tbody>
                            @foreach (var r in _parseResult.AcceptedRows)
                            {
                                <tr>
                                    <td><code>@r.ZTag</code></td>
                                    <td>@r.MachineCode</td>
                                    <td>@r.Name</td>
                                    <td>@r.UnsLineName</td>
                                </tr>
                            }
                            </tbody>
                        </table>
                    }
                </div>
            </div>
        </div>
        <div class="col-md-6">
            <div class="card">
                <div class="card-header bg-danger text-white">
                    Rejected (@_parseResult.RejectedRows.Count)
                </div>
                <div class="card-body p-0" style="max-height: 400px; overflow-y: auto;">
                    @if (_parseResult.RejectedRows.Count == 0)
                    {
                        <p class="text-muted p-3 mb-0">No rejections.</p>
                    }
                    else
                    {
                        <table class="table table-sm table-striped mb-0">
                            <thead><tr><th>Line</th><th>Reason</th></tr></thead>
                            <tbody>
                            @foreach (var e in _parseResult.RejectedRows)
                            {
                                <tr>
                                    <td>@e.LineNumber</td>
                                    <td class="small">@e.Reason</td>
                                </tr>
                            }
                            </tbody>
                        </table>
                    }
                </div>
            </div>
        </div>
    </div>
}

@code {
    [Parameter] public string ClusterId { get; set; } = string.Empty;
    [Parameter] public long GenerationId { get; set; }

    private List<DriverInstance>? _drivers;
    private List<UnsLine>? _unsLines;
    private string _driverInstanceId = string.Empty;
    private string _unsLineId = string.Empty;
    private string _csvText = string.Empty;
    private EquipmentCsvParseResult? _parseResult;
    private string? _parseError;
    private string? _result;
    private bool _busy;

    protected override async Task OnInitializedAsync()
    {
        _drivers = await DriverSvc.ListAsync(GenerationId, CancellationToken.None);
        _unsLines = await UnsSvc.ListLinesAsync(GenerationId, CancellationToken.None);
    }

    private async Task HandleFileAsync(InputFileChangeEventArgs e)
    {
        // 5 MiB cap — refuses pathological uploads that would OOM the server.
        using var stream = e.File.OpenReadStream(maxAllowedSize: 5 * 1024 * 1024);
        using var reader = new StreamReader(stream);
        _csvText = await reader.ReadToEndAsync();
    }

    private void ParseAsync()
    {
        _parseError = null;
        _parseResult = null;
        _result = null;
        try { _parseResult = EquipmentCsvImporter.Parse(_csvText); }
        catch (InvalidCsvFormatException ex) { _parseError = ex.Message; }
        catch (Exception ex) { _parseError = $"Parse failed: {ex.Message}"; }
    }

    private async Task StageAndFinaliseAsync()
    {
        if (_parseResult is null) return;
        _busy = true;
        _result = null;
        _parseError = null;
        try
        {
            var auth = await AuthProvider.GetAuthenticationStateAsync();
            var createdBy = auth.User.Identity?.Name ?? "unknown";

            var batch = await BatchSvc.CreateBatchAsync(ClusterId, createdBy, CancellationToken.None);
            await BatchSvc.StageRowsAsync(batch.Id, _parseResult.AcceptedRows, _parseResult.RejectedRows, CancellationToken.None);
            await BatchSvc.FinaliseBatchAsync(batch.Id, GenerationId, _driverInstanceId, _unsLineId, CancellationToken.None);

            _result = $"Finalised batch {batch.Id:N} — {_parseResult.AcceptedRows.Count} rows added.";
            // Pause 600 ms so the success banner is visible, then navigate back.
            await Task.Delay(600);
            Nav.NavigateTo($"/clusters/{ClusterId}/draft/{GenerationId}");
        }
        catch (Exception ex) { _parseError = $"Finalise failed: {ex.Message}"; }
        finally { _busy = false; }
    }
}
