UI/Controls/ResourceSelectPopup.razor
@using Sandbox;
@using Sandbox.UI;
@namespace Sandbox
@inherits BasePopup

<root class="popup">

    <div class="inner" onclick:preventDefault=@true>
        
        <div class="popup-header">
            <h2>@Title</h2>
            @if (AllowPackages)
            {
                <div class="sort-buttons">
                    @foreach ( var mode in Enum.GetValues<PackageSortMode>() )
                    {
                        var m = mode;
                        <div class="sort-button @(SortMode == m ? "active" : "")" @onclick=@(() => SetSort(m))>@m.ToString()</div>
                    }
                </div>
            }
        </div>

        <VirtualGrid Items=@(_filteredItems) ItemSize=@(new Vector2( 180, 200 )) class="grid">
            <Item Context="item">
                @if (item is Resource res)
                {
                    bool selected = res.ResourcePath.Equals(_pendingValue ?? CurrentValue, StringComparison.OrdinalIgnoreCase);
                    string itemClass = selected ? "item active" : "item";
                    string thumbUrl = $"thumb:{res.ResourcePath}";

                    <div @[email protected] class="@itemClass" @onclick=@(() => { OnItemClicked(res); })>

                        <div class="icon" style="background-image: url( @thumbUrl )"></div>

                        @if ( res is IDefinitionResource definitionResource )
                        {
                            <div class="title">@definitionResource.Title</div>
                            <div class="desc">@definitionResource.Description</div>
                        }
                        else
                        {
                            <div class="title">@res.ResourceName</div>
                            <div class="desc"></div>
                        }
                        
                    </div>
                }
                else if ( item is Package pkg )
                {
                    bool selected = pkg.FullIdent.Equals(CurrentValue, StringComparison.OrdinalIgnoreCase);
                    string itemClass = selected ? "item active" : "item";

                    <div @[email protected] class="@itemClass" @onclick=@(() => { SelectPackage(pkg); })>

                        <div class="icon" style="background-image: url( @pkg.Thumb )"></div>
                        <div class="title">@pkg.Title</div>
                        <div class="desc">@pkg.Org.Title</div>
                        
                    </div>
                }
            </Item>
        </VirtualGrid>

        <div class="popup-footer">
            <div class="clear-button" @onclick=@ClearSelection>Clear</div>
            <div class="select-button" @onclick=@ConfirmSelection>Select</div>
        </div>

    </div>

</root>

@code
{
    public string Title { get; set; } = "Select Resource";
    public string Extension { get; set; } = "vmdl";
    public string CurrentValue { get; set; }
    public bool AllowPackages { get; set; }
    public Action<string> OnSelectedFile;

    string _pendingValue;
    IResourcePreview _previewingResource;

    public string Category { get; set; }

    PackageSortMode SortMode { get; set; } = PackageSortMode.Popular;

    void SetSort( PackageSortMode mode )
    {
        if ( SortMode == mode ) return;
        SortMode = mode;
        if ( AllowPackages )
            _ = LoadCloudPackages();
    }

    readonly List<Resource> _localResources = new();
    readonly List<Package> _cloudPackages = new();
    List<object> _filteredItems = new();

    protected override void OnParametersSet()
    {
        _localResources.Clear();
        _cloudPackages.Clear();

        _localResources.AddRange( ResourceLibrary.GetAll<Resource>().Where( FilterExtension ).Where( FilterCategory ) );

        RebuildFilteredItems();

        if ( AllowPackages )
        {
            _ = LoadCloudPackages();
        }
    }

    void RebuildFilteredItems()
    {
        var items = new List<object>();
        items.AddRange( _localResources );
        items.AddRange( _cloudPackages );
        _filteredItems = items;
    }

    async Task LoadCloudPackages()
    {
        var query = $"sort:{SortMode.ToIdentifier()} type:{Extension}";

        var result = await Package.FindAsync( query );

        _cloudPackages.Clear();
        if ( result?.Packages != null )
        {
            _cloudPackages.AddRange( result.Packages );
        }

        RebuildFilteredItems();
        StateHasChanged();
    }

    bool FilterExtension(Resource res)
    {
        if (res == null) return false;
        if (string.IsNullOrEmpty(Extension)) return true;

        var ext = System.IO.Path.GetExtension(res.ResourcePath);
        if (string.IsNullOrEmpty(ext)) return false;

        return ext.TrimStart('.').Equals(Extension, StringComparison.OrdinalIgnoreCase);
    }

    bool FilterCategory(Resource res)
    {
        if (string.IsNullOrEmpty(Category)) return true;
        if (res is not SoundDefinition soundDef) return true;

        return string.Equals(soundDef.Category, Category, StringComparison.OrdinalIgnoreCase);
    }

    void OnItemClicked( Resource res )
    {
        StopPreview();

        _pendingValue = res.ResourcePath;

        var gameRes = ResourceLibrary.Get<GameResource>( res.ResourcePath );
        if ( gameRes is IResourcePreview preview )
        {
            _previewingResource = preview;
            preview.OnPreview();
        }

        StateHasChanged();
    }

    void StopPreview()
    {
        _previewingResource?.OnPreviewStop();
        _previewingResource = null;
    }

    public override void OnDeleted()
    {
        StopPreview();
        base.OnDeleted();
    }

    void ClearSelection()
    {
        StopPreview();
        _pendingValue = null;
        OnSelectedFile?.Invoke( null );
        StateHasChanged();
    }

    void ConfirmSelection()
    {
        StopPreview();

        if ( _pendingValue != null )
        {
            OnSelectedFile?.Invoke( _pendingValue );
            Delete();
        }
    }

    protected override void OnMouseDown(MousePanelEvent e)
    {
        base.OnMouseDown(e);

        if (e.Target == this)
        {
            StopPreview();
            Delete();
        }
    }

    void SelectResource(Resource res)
    {
        OnSelectedFile?.Invoke(res.ResourcePath);
        Delete();
    }

    void SelectPackage(Package pkg)
    {
        OnSelectedFile?.Invoke(pkg.FullIdent);
        Delete();
    }

}