@* OPC UA Client address picker:
     1. Manual NodeId entry (always available)
     2. (DriverOperator-gated) Browse remote server with live tree, lazy expand. *@
@implements IAsyncDisposable
@using Microsoft.AspNetCore.Authorization
@using ZB.MOM.WW.OtOpcUa.AdminUI.Browsing
@using ZB.MOM.WW.OtOpcUa.Commons.Browsing
@inject IBrowserSessionService BrowserService
@inject AuthenticationStateProvider AuthState
@inject IAuthorizationService AuthorizationService

<div class="row g-3">
    <div class="col-md-10">
        <label class="form-label">NodeId</label>
        <input type="text" class="form-control form-control-sm mono"
               placeholder="ns=2;s=Channel.Device.Tag"
               @bind="_nodeId" @bind:after="OnChangedAsync" />
        <div class="form-text">
            OPC UA NodeId string, e.g. <code>ns=2;s=Channel.Device.Tag</code> or
            <code>i=1001</code>. Use Browse to navigate the remote server.
        </div>
    </div>
</div>

@if (_canOperate)
{
    <div class="mt-3 d-flex align-items-center gap-2">
        @if (_token == Guid.Empty)
        {
            <button type="button" class="btn btn-outline-primary btn-sm"
                    disabled="@_opening" @onclick="OpenBrowseAsync">
                @if (_opening) { <span class="spinner-border spinner-border-sm me-1"></span> }
                Browse remote server
            </button>
        }
        else
        {
            <span class="chip chip-ok">Browser open</span>
            <button type="button" class="btn btn-outline-secondary btn-sm" @onclick="CloseBrowseAsync">
                Close
            </button>
        }
        @if (_openError is not null) { <span class="chip chip-bad" title="@_openError">@TruncatedError()</span> }
    </div>

    @if (_token != Guid.Empty)
    {
        <div class="mt-2">
            <DriverBrowseTree SessionToken="_token" OnNodeSelected="OnTreeSelectAsync"
                              SelectedNodeId="_nodeId" />
        </div>
    }
}

<div class="mt-3">
    <span class="text-muted small">Result:</span>
    <code class="mono ms-2">@_built</code>
</div>

@code {
    [Parameter] public string CurrentAddress { get; set; } = "";
    [Parameter] public EventCallback<string> CurrentAddressChanged { get; set; }
    [Parameter, EditorRequired] public Func<string> GetConfigJson { get; set; } = () => "{}";

    private string _nodeId = "";
    private string _built = "";
    private Guid _token = Guid.Empty;
    private bool _opening;
    private bool _canOperate;
    private string? _openError;

    protected override async Task OnInitializedAsync()
    {
        var auth = await AuthState.GetAuthenticationStateAsync();
        var authResult = await AuthorizationService.AuthorizeAsync(auth.User, null, "DriverOperator");
        _canOperate = authResult.Succeeded;
        _built = _nodeId;
        await CurrentAddressChanged.InvokeAsync(_built);
    }

    private async Task OpenBrowseAsync()
    {
        _opening = true; _openError = null; StateHasChanged();
        try
        {
            var json = GetConfigJson() ?? "{}";
            var result = await BrowserService.OpenAsync("OpcUaClient", json, default);
            if (result.Ok) _token = result.Token;
            else _openError = result.Message;
        }
        finally { _opening = false; StateHasChanged(); }
    }

    private async Task CloseBrowseAsync()
    {
        var t = _token; _token = Guid.Empty; StateHasChanged();
        if (t != Guid.Empty) await BrowserService.CloseAsync(t);
    }

    private async Task OnTreeSelectAsync(BrowseNode node)
    {
        _nodeId = node.NodeId;
        await OnChangedAsync();
    }

    private async Task OnChangedAsync()
    {
        _built = _nodeId;
        await CurrentAddressChanged.InvokeAsync(_built);
    }

    private string TruncatedError() =>
        _openError is null ? "" : (_openError.Length > 60 ? _openError[..60] + "…" : _openError);

    public ValueTask DisposeAsync()
    {
        if (_token != Guid.Empty)
        {
            // Fire-and-forget — don't block circuit teardown on a slow remote.
            _ = BrowserService.CloseAsync(_token);
        }
        return ValueTask.CompletedTask;
    }
}
