@page "/design/connections"
@page "/design/data-connections"
@using ScadaLink.Security
@using ScadaLink.Commons.Entities.Sites
@using ScadaLink.Commons.Interfaces.Repositories
@attribute [Authorize(Policy = AuthorizationPolicies.RequireDesign)]
@inject ISiteRepository SiteRepository
@inject NavigationManager NavigationManager
@inject IDialogService Dialog

<div class="container-fluid mt-3">
    <div class="d-flex justify-content-between align-items-center mb-3">
        <h4 class="mb-0">Connections</h4>
        <div class="d-flex gap-2">
            <div class="dropdown">
                <button class="btn btn-outline-secondary btn-sm dropdown-toggle"
                        data-bs-toggle="dropdown">
                    Bulk actions
                </button>
                <ul class="dropdown-menu dropdown-menu-end">
                    <li>
                        <button class="dropdown-item" @onclick="() => _tree?.ExpandAll()">
                            Expand all
                        </button>
                    </li>
                    <li>
                        <button class="dropdown-item" @onclick="() => _tree?.CollapseAll()">
                            Collapse all
                        </button>
                    </li>
                </ul>
            </div>
            <button class="btn btn-primary btn-sm"
                    disabled="@(!HasSiteSelected)"
                    @onclick="OnAddConnectionClicked">+ Connection</button>
        </div>
    </div>

    <ToastNotification @ref="_toast" />

    @if (_loading)
    {
        <LoadingSpinner IsLoading="true" />
    }
    else if (_errorMessage != null)
    {
        <div class="alert alert-danger">@_errorMessage</div>
    }
    else
    {
        <div class="mb-3" style="max-width: 320px;">
            <input type="text" class="form-control form-control-sm"
                   placeholder="Search sites or connections..."
                   @bind="_searchText" @bind:event="oninput" @bind:after="OnSearchChanged" />
        </div>

        @if (!string.IsNullOrWhiteSpace(_searchText) && _matchKeys.Count == 0 && _treeRoots.Count > 0)
        {
            <p class="text-muted small">No connections match the filter.</p>
        }

        <TreeView @ref="_tree" TItem="DcTreeNode" Items="_treeRoots"
                  ChildrenSelector="n => n.Children"
                  HasChildrenSelector="n => n.Children.Count > 0"
                  KeySelector="n => (object)n.Key"
                  StorageKey="data-connections-tree"
                  Selectable="true"
                  SelectedKey="_selectedKey"
                  SelectedKeyChanged="OnTreeNodeSelected">
            <NodeContent Context="node">
                @{
                    var labelStyle = IsDimmed(node) ? "opacity: 0.4;" : "";
                }
                @if (node.Kind == DcNodeKind.Site)
                {
                    <span class="tv-label fw-semibold" style="@labelStyle">@node.Label</span>
                    <span class="badge bg-secondary ms-1">@node.Children.Count</span>
                }
                else
                {
                    <span class="tv-label" style="@labelStyle">@node.Label</span>
                    <span class="badge bg-info ms-2">@node.Connection!.Protocol</span>
                }
                <span class="tv-meta">
                    <div class="dropdown dc-node-actions" @onclick:stopPropagation="true">
                        <button type="button"
                                class="btn btn-link btn-sm p-0 dc-kebab"
                                data-bs-toggle="dropdown"
                                aria-label="@($"More actions for {node.Label}")">⋮</button>
                        <ul class="dropdown-menu dropdown-menu-end">
                            @if (node.Kind == DcNodeKind.Site)
                            {
                                <li>
                                    <button class="dropdown-item"
                                            @onclick="() => AddConnectionForSite(node.SiteId!.Value)">
                                        Add Connection here
                                    </button>
                                </li>
                            }
                            else
                            {
                                <li>
                                    <button class="dropdown-item"
                                            @onclick='() => NavigationManager.NavigateTo($"/design/connections/{node.Connection!.Id}/edit")'>
                                        Edit
                                    </button>
                                </li>
                                <li><hr class="dropdown-divider" /></li>
                                <li>
                                    <button class="dropdown-item text-danger"
                                            @onclick="() => DeleteConnection(node.Connection!)">
                                        Delete
                                    </button>
                                </li>
                            }
                        </ul>
                    </div>
                </span>
            </NodeContent>
            <ContextMenu Context="node">
                @if (node.Kind == DcNodeKind.Site)
                {
                    <button class="dropdown-item"
                            @onclick="() => AddConnectionForSite(node.SiteId!.Value)">
                        Add Connection here
                    </button>
                }
                else
                {
                    <button class="dropdown-item"
                            @onclick='() => NavigationManager.NavigateTo($"/design/connections/{node.Connection!.Id}/edit")'>
                        Edit
                    </button>
                    <div class="dropdown-divider"></div>
                    <button class="dropdown-item text-danger"
                            @onclick="() => DeleteConnection(node.Connection!)">
                        Delete
                    </button>
                }
            </ContextMenu>
            <EmptyContent>
                <span class="text-muted fst-italic">No sites configured. Add sites under Admin → Sites.</span>
            </EmptyContent>
        </TreeView>

        <div class="text-muted small mt-2">
            @_connections.Count connection(s) across @_treeRoots.Count site(s).
        </div>
    }
</div>

<style>
    /* Kebab visible-on-hover for tree nodes; always visible at small sizes for touch. */
    .dc-node-actions .dc-kebab {
        opacity: 0;
        line-height: 1;
        padding: 0 0.25rem !important;
        color: var(--bs-secondary-color);
    }
    .tv-row:hover .dc-node-actions .dc-kebab,
    .dc-node-actions.show .dc-kebab,
    .dc-node-actions .dc-kebab:focus {
        opacity: 1;
    }
    @@media (max-width: 768px) {
        .dc-node-actions .dc-kebab { opacity: 1; }
    }
</style>

@code {
    record DcTreeNode(string Key, string Label, DcNodeKind Kind, List<DcTreeNode> Children,
        int? SiteId = null, DataConnection? Connection = null);
    enum DcNodeKind { Site, DataConnection }

    private List<DcTreeNode> _treeRoots = new();
    private List<DataConnection> _connections = new();
    private bool _loading = true;
    private string? _errorMessage;

    private TreeView<DcTreeNode>? _tree;
    private object? _selectedKey;
    private string _searchText = string.Empty;
    private HashSet<string> _matchKeys = new();

    private ToastNotification _toast = default!;

    private bool HasSiteSelected => ResolveSelectedSiteId() != null;

    protected override async Task OnInitializedAsync()
    {
        await LoadDataAsync();
    }

    private async Task LoadDataAsync()
    {
        _loading = true;
        _errorMessage = null;
        try
        {
            var sites = await SiteRepository.GetAllSitesAsync();
            _connections = (await SiteRepository.GetAllDataConnectionsAsync()).ToList();

            var connBySite = _connections.GroupBy(c => c.SiteId).ToDictionary(g => g.Key, g => g.ToList());
            _treeRoots = sites.Select(site => new DcTreeNode(
                Key: $"site-{site.Id}",
                Label: site.Name,
                Kind: DcNodeKind.Site,
                Children: (connBySite.GetValueOrDefault(site.Id) ?? new())
                    .Select(c => new DcTreeNode(
                        Key: $"conn-{c.Id}",
                        Label: c.Name,
                        Kind: DcNodeKind.DataConnection,
                        Children: new(),
                        SiteId: c.SiteId,
                        Connection: c))
                    .ToList(),
                SiteId: site.Id
            )).ToList();
            RebuildMatchKeys();
        }
        catch (Exception ex)
        {
            _errorMessage = $"Failed to load data: {ex.Message}";
        }
        _loading = false;
    }

    private void OnTreeNodeSelected(object? key)
    {
        _selectedKey = key;
    }

    private int? ResolveSelectedSiteId()
    {
        if (_selectedKey is not string keyStr) return null;
        foreach (var site in _treeRoots)
        {
            if (site.Key == keyStr) return site.SiteId;
            foreach (var child in site.Children)
            {
                if (child.Key == keyStr) return site.SiteId;
            }
        }
        return null;
    }

    private void OnAddConnectionClicked()
    {
        var sid = ResolveSelectedSiteId();
        if (sid == null) return;
        AddConnectionForSite(sid.Value);
    }

    private void AddConnectionForSite(int siteId)
    {
        NavigationManager.NavigateTo($"/design/connections/create?siteId={siteId}");
    }

    private void OnSearchChanged()
    {
        RebuildMatchKeys();
    }

    private void RebuildMatchKeys()
    {
        _matchKeys.Clear();
        if (string.IsNullOrWhiteSpace(_searchText)) return;
        var q = _searchText.Trim();
        foreach (var root in _treeRoots)
        {
            SubtreeContainsMatch(root, q);
        }
    }

    private bool SubtreeContainsMatch(DcTreeNode node, string query)
    {
        var selfMatch = node.Label.Contains(query, StringComparison.OrdinalIgnoreCase);
        var childMatch = false;
        foreach (var child in node.Children)
        {
            if (SubtreeContainsMatch(child, query)) childMatch = true;
        }
        if (selfMatch || childMatch) _matchKeys.Add(node.Key);
        return selfMatch || childMatch;
    }

    private bool IsDimmed(DcTreeNode node)
    {
        if (string.IsNullOrWhiteSpace(_searchText)) return false;
        return !_matchKeys.Contains(node.Key);
    }

    private async Task DeleteConnection(DataConnection conn)
    {
        var confirmed = await Dialog.ConfirmAsync(
            "Delete Connection",
            $"Delete data connection '{conn.Name}'?",
            danger: true);
        if (!confirmed) return;

        try
        {
            await SiteRepository.DeleteDataConnectionAsync(conn.Id);
            await SiteRepository.SaveChangesAsync();
            _toast.ShowSuccess($"Connection '{conn.Name}' deleted.");
            await LoadDataAsync();
        }
        catch (Exception ex)
        {
            _toast.ShowError($"Delete failed: {ex.Message}");
        }
    }
}
