@using ZB.MOM.WW.OtOpcUa.Admin.Services
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
@inject UnsService UnsSvc

<div class="alert alert-info small mb-3">
    Drag any line in the <strong>UNS Lines</strong> table onto an area row in <strong>UNS Areas</strong>
    to re-parent it. A preview modal shows the impact (equipment re-home count) + lets you confirm
    or cancel. If another operator modifies the draft while you're confirming, you'll see a 409
    refresh-required modal instead of clobbering their work.
</div>

<div class="row">
    <div class="col-md-6">
        <div class="d-flex justify-content-between mb-2">
            <h4>UNS Areas</h4>
            <button class="btn btn-sm btn-primary" @onclick="() => _showAreaForm = true">Add area</button>
        </div>

        @if (_areas is null) { <p>Loading…</p> }
        else if (_areas.Count == 0) { <p class="text-muted">No areas yet.</p> }
        else
        {
            <table class="table table-sm">
                <thead><tr><th>AreaId</th><th>Name</th><th class="small text-muted">(drop target)</th></tr></thead>
                <tbody>
                @foreach (var a in _areas)
                {
                    <tr class="@(_hoverAreaId == a.UnsAreaId ? "table-primary" : "")"
                        @ondragover="e => OnAreaDragOver(e, a.UnsAreaId)"
                        @ondragover:preventDefault
                        @ondragleave="() => _hoverAreaId = null"
                        @ondrop="() => OnLineDroppedAsync(a.UnsAreaId)"
                        @ondrop:preventDefault>
                        <td><code>@a.UnsAreaId</code></td>
                        <td>@a.Name</td>
                        <td class="small text-muted">drop here</td>
                    </tr>
                }
                </tbody>
            </table>
        }

        @if (_showAreaForm)
        {
            <div class="card">
                <div class="card-body">
                    <div class="mb-2"><label class="form-label">Name (lowercase segment)</label><input class="form-control" @bind="_newAreaName"/></div>
                    <button class="btn btn-sm btn-primary" @onclick="AddAreaAsync">Save</button>
                    <button class="btn btn-sm btn-secondary ms-2" @onclick="() => _showAreaForm = false">Cancel</button>
                </div>
            </div>
        }
    </div>

    <div class="col-md-6">
        <div class="d-flex justify-content-between mb-2">
            <h4>UNS Lines</h4>
            <button class="btn btn-sm btn-primary" @onclick="() => _showLineForm = true" disabled="@(_areas is null || _areas.Count == 0)">Add line</button>
        </div>

        @if (_lines is null) { <p>Loading…</p> }
        else if (_lines.Count == 0) { <p class="text-muted">No lines yet.</p> }
        else
        {
            <table class="table table-sm">
                <thead><tr><th>LineId</th><th>Area</th><th>Name</th></tr></thead>
                <tbody>
                @foreach (var l in _lines)
                {
                    <tr draggable="true"
                        @ondragstart="() => _dragLineId = l.UnsLineId"
                        @ondragend="() => { _dragLineId = null; _hoverAreaId = null; }"
                        style="cursor: grab;">
                        <td><code>@l.UnsLineId</code></td>
                        <td><code>@l.UnsAreaId</code></td>
                        <td>@l.Name</td>
                    </tr>
                }
                </tbody>
            </table>
        }

        @if (_showLineForm && _areas is not null)
        {
            <div class="card">
                <div class="card-body">
                    <div class="mb-2">
                        <label class="form-label">Area</label>
                        <select class="form-select" @bind="_newLineAreaId">
                            @foreach (var a in _areas) { <option value="@a.UnsAreaId">@a.Name (@a.UnsAreaId)</option> }
                        </select>
                    </div>
                    <div class="mb-2"><label class="form-label">Name</label><input class="form-control" @bind="_newLineName"/></div>
                    <button class="btn btn-sm btn-primary" @onclick="AddLineAsync">Save</button>
                    <button class="btn btn-sm btn-secondary ms-2" @onclick="() => _showLineForm = false">Cancel</button>
                </div>
            </div>
        }
    </div>
</div>

@* Preview / confirm modal for a pending drag-drop move *@
@if (_pendingPreview is not null)
{
    <div class="modal show d-block" tabindex="-1" style="background-color: rgba(0,0,0,0.5);">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Confirm UNS move</h5>
                    <button type="button" class="btn-close" @onclick="CancelMove"></button>
                </div>
                <div class="modal-body">
                    <p>@_pendingPreview.HumanReadableSummary</p>
                    <p class="text-muted small">
                        Equipment re-homed: <strong>@_pendingPreview.AffectedEquipmentCount</strong>.
                        Tags re-parented: <strong>@_pendingPreview.AffectedTagCount</strong>.
                    </p>
                    @if (_pendingPreview.CascadeWarnings.Count > 0)
                    {
                        <div class="alert alert-warning small mb-0">
                            <ul class="mb-0">
                                @foreach (var w in _pendingPreview.CascadeWarnings) { <li>@w</li> }
                            </ul>
                        </div>
                    }
                </div>
                <div class="modal-footer">
                    <button class="btn btn-secondary" @onclick="CancelMove">Cancel</button>
                    <button class="btn btn-primary" @onclick="ConfirmMoveAsync" disabled="@_committing">Confirm move</button>
                </div>
            </div>
        </div>
    </div>
}

@* 409 concurrent-edit modal — another operator changed the draft between preview + commit *@
@if (_conflictMessage is not null)
{
    <div class="modal show d-block" tabindex="-1" style="background-color: rgba(0,0,0,0.5);">
        <div class="modal-dialog">
            <div class="modal-content border-danger">
                <div class="modal-header bg-danger text-white">
                    <h5 class="modal-title">Draft changed — refresh required</h5>
                </div>
                <div class="modal-body">
                    <p>@_conflictMessage</p>
                    <p class="small text-muted">
                        Concurrency guard per DraftRevisionToken prevented overwriting the peer
                        operator's edit. Reload the tab + redo the move on the current draft state.
                    </p>
                </div>
                <div class="modal-footer">
                    <button class="btn btn-primary" @onclick="ReloadAfterConflict">Reload draft</button>
                </div>
            </div>
        </div>
    </div>
}

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

    private List<UnsArea>? _areas;
    private List<UnsLine>? _lines;
    private bool _showAreaForm;
    private bool _showLineForm;
    private string _newAreaName = string.Empty;
    private string _newLineName = string.Empty;
    private string _newLineAreaId = string.Empty;

    private string? _dragLineId;
    private string? _hoverAreaId;
    private UnsImpactPreview? _pendingPreview;
    private UnsMoveOperation? _pendingMove;
    private bool _committing;
    private string? _conflictMessage;

    protected override async Task OnParametersSetAsync() => await ReloadAsync();

    private async Task ReloadAsync()
    {
        _areas = await UnsSvc.ListAreasAsync(GenerationId, CancellationToken.None);
        _lines = await UnsSvc.ListLinesAsync(GenerationId, CancellationToken.None);
    }

    private async Task AddAreaAsync()
    {
        if (string.IsNullOrWhiteSpace(_newAreaName)) return;
        await UnsSvc.AddAreaAsync(GenerationId, ClusterId, _newAreaName, notes: null, CancellationToken.None);
        _newAreaName = string.Empty;
        _showAreaForm = false;
        await ReloadAsync();
    }

    private async Task AddLineAsync()
    {
        if (string.IsNullOrWhiteSpace(_newLineName) || string.IsNullOrWhiteSpace(_newLineAreaId)) return;
        await UnsSvc.AddLineAsync(GenerationId, _newLineAreaId, _newLineName, notes: null, CancellationToken.None);
        _newLineName = string.Empty;
        _showLineForm = false;
        await ReloadAsync();
    }

    private void OnAreaDragOver(DragEventArgs _, string areaId) => _hoverAreaId = areaId;

    private async Task OnLineDroppedAsync(string targetAreaId)
    {
        var lineId = _dragLineId;
        _hoverAreaId = null;
        _dragLineId = null;
        if (string.IsNullOrWhiteSpace(lineId)) return;

        var line = _lines?.FirstOrDefault(l => l.UnsLineId == lineId);
        if (line is null || line.UnsAreaId == targetAreaId) return;

        var snapshot = await UnsSvc.LoadSnapshotAsync(GenerationId, CancellationToken.None);
        var move = new UnsMoveOperation(
            Kind: UnsMoveKind.LineMove,
            SourceClusterId: ClusterId,
            TargetClusterId: ClusterId,
            SourceLineId: lineId,
            TargetAreaId: targetAreaId);
        try
        {
            _pendingPreview = UnsImpactAnalyzer.Analyze(snapshot, move);
            _pendingMove = move;
        }
        catch (Exception ex)
        {
            _conflictMessage = ex.Message; // CrossCluster or validation failure surfaces here
        }
    }

    private void CancelMove()
    {
        _pendingPreview = null;
        _pendingMove = null;
    }

    private async Task ConfirmMoveAsync()
    {
        if (_pendingPreview is null || _pendingMove is null) return;
        _committing = true;
        try
        {
            await UnsSvc.MoveLineAsync(
                GenerationId,
                _pendingPreview.RevisionToken,
                _pendingMove.SourceLineId!,
                _pendingMove.TargetAreaId!,
                CancellationToken.None);

            _pendingPreview = null;
            _pendingMove = null;
            await ReloadAsync();
        }
        catch (DraftRevisionConflictException ex)
        {
            _pendingPreview = null;
            _pendingMove = null;
            _conflictMessage = ex.Message;
        }
        finally { _committing = false; }
    }

    private async Task ReloadAfterConflict()
    {
        _conflictMessage = null;
        await ReloadAsync();
    }
}
