#pragma once

#include "CoreMinimal.h"
#include "WingServer.h"
#include "WingBasics.h"
#include "WingUtils.h"
#include "WingTypes.h"
#include "AssetRegistry/AssetRegistryModule.h"
#include "AssetRegistry/AssetData.h"
#include "AssetRegistry/IAssetRegistry.h"
#include "Asset_Search.generated.h"


// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------

UCLASS()
class UWing_Asset_Search : public UWingHandler
{
	GENERATED_BODY()

public:
	UPROPERTY(EditAnywhere, meta=(Description="Substring to match against asset package paths"))
	FString Query;

	UPROPERTY(EditAnywhere, meta=(Description="Asset class name to filter by, e.g. Blueprint, Material, StaticMesh"))
	FString Type;

	UPROPERTY(EditAnywhere, meta=(Description="Maximum number of results (default 50)"))
	int32 Limit = 50;

	virtual void Register() override
	{
		UWingServer::AddHandler(this,
			TEXT("Search for assets by name and/or type. At least one of Query or Type must be specified."));
	}
	virtual void Handle() override
	{
		if (Query.IsEmpty() && Type.IsEmpty())
		{
			WingOut::Stdout.Print(TEXT("ERROR: At least one of Query or Type must be specified\n"));
			return;
		}

		// Build the asset registry filter
		FARFilter Filter;
		Filter.bRecursiveClasses = true;
		Filter.bRecursivePaths = true;
		Filter.PackagePaths.Add(FName(TEXT("/Game")));

		if (!Type.IsEmpty())
		{
			UWingTypes::Requirements Req;
			Req.AllowContainer = false;
			Req.IsChildOf = UObject::StaticClass();
			FEdGraphPinType PinType;
			if (!UWingTypes::TextToType(Type, PinType, Req, WingOut::Stdout)) return;
			UClass* TypeClass = Cast<UClass>(PinType.PinSubCategoryObject.Get());
			check(TypeClass);
			Filter.ClassPaths.Add(TypeClass->GetClassPathName());
		}

		// Query the asset registry
		IAssetRegistry& AR = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry").Get();
		TArray<FAssetData> Candidates;
		AR.GetAssets(Filter, Candidates);

		// Filter by query substring and collect results
		TArray<FAssetData> Results;
		for (const FAssetData& Data : Candidates)
		{
			if (Results.Num() >= Limit) break;
			if (!Query.IsEmpty())
			{
				if (!Data.AssetName.ToString().Contains(Query, ESearchCase::IgnoreCase) &&
					!Data.PackageName.ToString().Contains(Query, ESearchCase::IgnoreCase))
					continue;
			}
			Results.Add(Data);
		}

		for (const FAssetData& Data : Results)
		{
			WingOut::Stdout.Printf(TEXT("%s %s\n"),
				*WingUtils::FormatName(Data.GetClass()),
				*Data.PackageName.ToString());
		}

		if (Results.Num() == 0)
		{
			WingOut::Stdout.Print(TEXT("No assets found.\n"));
		}
		else if (Results.Num() >= Limit)
		{
			WingOut::Stdout.Printf(TEXT("WARNING: You reached the limit of %d, to raise it, specify the Limit parameter.\n"), Limit);
		}
	}
};
