// Copyright Dominik Pavlicek 2023. All Rights Reserved.

#pragma once

#include "Search/ComboActionSearchResult.h"

#include "ComboActionGraph.h"
#include "AssetRegistry/IAssetRegistry.h"
#include "Ed/EdComboActionGraphNode.h"


struct FDialogueSearchData
{
	TWeakObjectPtr<class UComboActionGraph> Dialogue;
};

class FComboActionSearchManager
{
public:
	static FComboActionSearchManager *Get()
	{
		if (Instance == nullptr)
		{
			Instance = new FComboActionSearchManager();
		}
		return Instance;
	}

public:
	FComboActionSearchManager(){}
	~FComboActionSearchManager() { this->UnInitialize(); }

	/**
	 * Searches for InSearchString in the InGraphNode. Adds the result as a child in OutParentNode.
	 * @return True if found anything matching the InSearchString
	 */
	bool QueryGraphNode(const FComboActionSearchFilter &SearchFilter, const UEdComboActionGraphNode *InGraphNode, const TSharedPtr<class FComboActionSearchResult> &OutParentNode) const;

	bool QueryNodeDecorators
	(
		const FComboActionSearchFilter &SearchFilter,
		const FComboActionDecorator &InDecorator,
		const TSharedPtr<class FComboActionSearchResult> &OutParentNode,
		int32 DecoratorIndex,
		FName DecoratorMemberName
	) const;

	/**
	 * Searches for InSearchString in the InAction. Adds the result as a child of OutParentNode.
	 * @return True if found anything matching the InSearchString
	 */
	bool QuerySingleAction
	(
		const FComboActionSearchFilter &SearchFilter,
		const UComboActionGraph *InAction,
		TSharedPtr<class FComboActionSearchResult> &OutParentNode
	);
	
	void Initialize(TSharedPtr<FWorkspaceItem> ParentTabCategory = nullptr);
	
	void UnInitialize();

	private:
	
	// Helper method to make a Text Node and add it as a child to ParentNode
	TSharedPtr<FComboActionSearchResult> MakeChildTextNode
	(
		const TSharedPtr<FComboActionSearchResult> &ParentNode,
		const FText &DisplayName, const FText &Category,
		const FString &CommentString
	) const
	{
		TSharedPtr<FComboActionSearchResult> TextNode = MakeShared<FComboActionSearchResult>(DisplayName, ParentNode);
		TextNode->SetCategory(Category);
		if (!CommentString.IsEmpty())
		{
			TextNode->SetCommentString(CommentString);
		}
		ParentNode->AddChild(TextNode);
		return TextNode;
	}
	
	// Callback hook from the Asset Registry when an asset is added
	void HandleOnAssetAdded(const FAssetData &InAssetData){}

	// Callback hook from the Asset Registry, marks the asset for deletion from the cache
	void HandleOnAssetRemoved(const FAssetData &InAssetData){}

	// Callback hook from the Asset Registry, marks the asset for deletion from the cache
	void HandleOnAssetRenamed(const FAssetData &InAssetData, const FString &InOldName){}

	// Callback hook from the Asset Registry when an asset is loaded
	void HandleOnAssetLoaded(UObject *InAsset){}

	// Callback when the Asset Registry loads all its assets
	void HandleOnAssetRegistryFilesLoaded(){}

private:
	static FComboActionSearchManager *Instance;

	// Maps the Dialogue path => SearchData.
	TMap<FName, FDialogueSearchData> SearchMap;

	// Because we are unable to query for the module on another thread, cache it for use later
	IAssetRegistry *AssetRegistry = nullptr;

	// Handlers
	FDelegateHandle OnAssetAddedHandle;
	FDelegateHandle OnAssetRemovedHandle;
	FDelegateHandle OnAssetRenamedHandle;
	FDelegateHandle OnFilesLoadedHandle;
	FDelegateHandle OnAssetLoadedHandle;
};
