#pragma once

#include "CoreMinimal.h"
#include "Dom/JsonObject.h"
#include "HttpRouteHandle.h"
#include "HttpServerRequest.h"
#include "HttpResultCallback.h"

class IHttpRouter;
struct FHttpServerResponse;
class FJsonValue;

class FDruidsMCPBridgeServer : public TSharedFromThis<FDruidsMCPBridgeServer>
{
public:
	bool Start(uint16 PreferredPort = 8765);
	void Stop();

	bool IsRunning() const { return bRunning; }
	uint16 GetPort() const { return ActivePort; }
	FString GetEndpointUrl() const;

private:
	bool BindOnPort(uint16 Port);
	bool VerifyLocalPortListening(uint16 Port) const;
	bool HandleMCPRequest(const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete);
	void HandleMCPRequestOnGameThread(FString RequestBody, FHttpResultCallback OnComplete);

	TUniquePtr<FHttpServerResponse> MakeHttpJsonResponse(const FString& JsonText) const;
	TUniquePtr<FHttpServerResponse> MakeHttpErrorResponse(const FString& Message) const;

	TSharedPtr<FJsonObject> ProcessJsonRpcRequest(const TSharedPtr<FJsonObject>& RequestObject);
	TSharedPtr<FJsonObject> HandleInitialize(const TSharedPtr<FJsonObject>& RequestObject) const;
	TSharedPtr<FJsonObject> HandlePing(const TSharedPtr<FJsonObject>& RequestObject) const;
	TSharedPtr<FJsonObject> HandleToolsList(const TSharedPtr<FJsonObject>& RequestObject) const;
	TSharedPtr<FJsonObject> HandleToolsCall(const TSharedPtr<FJsonObject>& RequestObject);
	TSharedPtr<FJsonObject> HandleNotification(const TSharedPtr<FJsonObject>& RequestObject) const;

	TSharedPtr<FJsonObject> ExecuteTool(const FString& ToolName, const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteGetStatus() const;
	TSharedPtr<FJsonObject> ExecuteGetCapabilities() const;
	TSharedPtr<FJsonObject> ExecuteRecommendTools(const TSharedPtr<FJsonObject>& Arguments) const;
	TSharedPtr<FJsonObject> ExecuteSageListExtensions(const TSharedPtr<FJsonObject>& Arguments) const;
	TSharedPtr<FJsonObject> ExecuteSageSearchExtensions(const TSharedPtr<FJsonObject>& Arguments) const;
	TSharedPtr<FJsonObject> ExecuteSageGetExtensionDetails(const TSharedPtr<FJsonObject>& Arguments) const;
	TSharedPtr<FJsonObject> ExecuteSageCallQuery(const TSharedPtr<FJsonObject>& Arguments) const;
	TSharedPtr<FJsonObject> ExecuteSageCallAction(const TSharedPtr<FJsonObject>& Arguments) const;
	TSharedPtr<FJsonObject> ExecuteCreateBlueprint(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteCreateBlueprintInterface(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintCreateRoadActor(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintCreateIntersectionActor(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintCreateSkyscraperActor(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintCreatePrimitiveActor(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteCreateLongearsReproAssets(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteCreateMaterialReproAssets(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteResolveAsset(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteInspectAsset(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteDataAssetFindClasses(const TSharedPtr<FJsonObject>& Arguments) const;
	TSharedPtr<FJsonObject> ExecuteDataAssetCreate(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteDataAssetSetProperty(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteDataAssetCreateBatch(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteEditorGetWorldStatus(const TSharedPtr<FJsonObject>& Arguments) const;
	TSharedPtr<FJsonObject> ExecuteEditorPlaceActor(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteEditorSetActorTransform(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteEditorSetComponentTransform(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteEditorReadLevelActors(const TSharedPtr<FJsonObject>& Arguments) const;
	TSharedPtr<FJsonObject> ExecuteEditorSelectActor(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteEditorCleanupReproActors(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteEditorCaptureViewport(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecutePCGGetStatus(const TSharedPtr<FJsonObject>& Arguments) const;
	TSharedPtr<FJsonObject> ExecutePCGGetRoadCapabilities(const TSharedPtr<FJsonObject>& Arguments) const;
	TSharedPtr<FJsonObject> ExecutePCGCreateSplineBoundsActor(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecutePCGInspectSplineBoundsActor(const TSharedPtr<FJsonObject>& Arguments) const;
	TSharedPtr<FJsonObject> ExecutePCGSetSplineBoundsActor(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecutePCGCreateForestRepro(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecutePCGPlaceForestActor(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecutePCGInspectGraph(const TSharedPtr<FJsonObject>& Arguments) const;
	TSharedPtr<FJsonObject> ExecutePCGSetForestBounds(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecutePCGGenerate(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecutePCGCreateVisualReproOutput(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecutePCGInspectGenerated(const TSharedPtr<FJsonObject>& Arguments) const;
	TSharedPtr<FJsonObject> ExecutePCGRunForestRecipe(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecutePCGRunRoadRecipe(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecutePCGRunSplineRoadProof(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecutePCGRunCityLayoutRecipe(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecutePCGUpdateCityLayoutRecipe(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecutePCGUpdateForestRecipe(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecutePCGMultiClassProof(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteMaterialCreate(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteMaterialFindExpressionClasses(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteMaterialResolveExpressionClass(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteMaterialAddExpression(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteMaterialSetExpressionProperty(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteMaterialConnectExpressions(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteMaterialConnectRoot(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteMaterialUpdate(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintAddVariable(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintAddComponent(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintAddComponentMotion(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintAddDynamicMaterialParameterUpdate(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintCreateFunction(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintCreateEventGraph(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintImplementInterface(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintAddInterfaceEvent(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintAddCustomEvent(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintAddComment(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintReadGraph(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintCompile(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintFindNodeSpawners(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintResolveNodeSpawner(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintAddNode(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintSetNodePosition(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintConnectNodes(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintAddNodeBySearchAndConnect(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintSearchProject(const TSharedPtr<FJsonObject>& Arguments);
	TSharedPtr<FJsonObject> ExecuteBlueprintRunRecipe(const TSharedPtr<FJsonObject>& Arguments);

	TSharedPtr<FJsonObject> ResolveAssetToObject(const FString& NameOrPath, const FString& Type, int32 Limit, FString& OutAssetPath, FString& OutError);

	class UBlueprint* LoadBlueprint(const FString& AssetPath, FString& OutError) const;
	class UEdGraph* FindBlueprintGraph(class UBlueprint* Blueprint, const FString& GraphName, FString& OutError) const;
	TArray<TSharedPtr<FJsonValue>> MakeBlueprintGraphInventory(class UBlueprint* Blueprint, const FString& AssetPath = TEXT("")) const;
	TSharedPtr<FJsonObject> ReadBlueprintGraph(class UBlueprint* Blueprint, class UEdGraph* Graph) const;
	TArray<TSharedPtr<FJsonValue>> FindNativeNodeSpawners(class UBlueprint* Blueprint, const FString& Query, const FString& InputType, const FString& OutputType, int32 Limit) const;
	TSharedPtr<FJsonObject> AddNativeBlueprintNode(class UBlueprint* Blueprint, class UEdGraph* Graph, const FString& SpawnerId, const FString& NodeName, const TSharedPtr<FJsonObject>& PinDefaults, FString& OutError) const;
	bool ConnectNativeBlueprintPins(class UBlueprint* Blueprint, class UEdGraph* Graph, const FString& SourceNodeGuid, const FString& SourcePinName, const FString& TargetNodeGuid, const FString& TargetPinName, FString& OutError) const;

	TSharedPtr<FJsonObject> MakeJsonRpcResult(const TSharedPtr<FJsonObject>& RequestObject, const TSharedPtr<FJsonObject>& ResultObject) const;
	TSharedPtr<FJsonObject> MakeJsonRpcError(const TSharedPtr<FJsonObject>& RequestObject, int32 Code, const FString& Message) const;
	TSharedPtr<FJsonObject> MakeJsonRpcErrorWithId(const TSharedPtr<FJsonValue>& IdValue, int32 Code, const FString& Message) const;
	TSharedPtr<FJsonObject> MakeToolTextResult(const FString& Text, bool bIsError = false) const;
	TSharedPtr<FJsonObject> MakeToolJsonResult(const TSharedPtr<FJsonValue>& Value, bool bIsError = false) const;
	TSharedPtr<FJsonObject> MakeToolJsonObjectResult(const TSharedPtr<FJsonObject>& Object, bool bIsError = false) const;
	TSharedPtr<FJsonObject> BuildCapabilitiesManifest() const;

	TSharedPtr<FJsonObject> MakeToolDefinition(
		const FString& Name,
		const FString& Description,
		const TSharedPtr<FJsonObject>& InputSchema) const;
	TSharedPtr<FJsonObject> MakeObjectSchema() const;
	TSharedPtr<FJsonObject> MakeStringProperty(const FString& Description) const;
	TSharedPtr<FJsonObject> MakeObjectProperty(const FString& Description) const;

	static bool TryGetObjectParam(const TSharedPtr<FJsonObject>& Object, const FString& FieldName, TSharedPtr<FJsonObject>& OutObject);
	static FString GetOptionalStringParam(const TSharedPtr<FJsonObject>& Object, const FString& FieldName, const FString& DefaultValue = TEXT(""));
	static int32 GetOptionalIntParam(const TSharedPtr<FJsonObject>& Object, const FString& FieldName, int32 DefaultValue);
	static bool TextMatches(const FString& Haystack, const FString& Needle);
	static TSharedPtr<FJsonValue> ParseJsonString(const FString& JsonText);
	static TSharedPtr<FJsonObject> ParseJsonObjectString(const FString& JsonText);
	static TSharedPtr<FJsonObject> ExtractFirstObjectFromToolContent(const TSharedPtr<FJsonObject>& ToolObject);
	static TSharedPtr<FJsonObject> ParseOutResultObject(const TSharedPtr<FJsonObject>& Object);
	static TSharedPtr<FJsonObject> ParseGraphText(const FString& GraphText);
	static TArray<FString> SplitGraphPinList(const FString& PinText);
	static bool TryFindNodeGuidInGraphText(const FString& GraphText, const FString& TitleOrGuid, FString& OutNodeGuid);
	static bool TryFindStringFieldRecursive(const TSharedPtr<FJsonValue>& Value, const TArray<FString>& FieldNames, FString& OutString);
	static TSharedPtr<FJsonObject> FindNodeByTitleOrGuid(const TSharedPtr<FJsonValue>& Value, const FString& TitleOrGuid);
	static TSharedPtr<FJsonObject> FindFirstSpawnerNode(const TSharedPtr<FJsonObject>& SpawnerResult);
	static TArray<TSharedPtr<FJsonValue>> MakeStringArrayValue(const TArray<FString>& Strings);
	static TArray<FString> BuildSpawnerResolverQueries(const FString& Query, const FString& Intent, const FString& Operator, const FString& ValueType);
	static int32 ScoreSpawnerCandidate(const TSharedPtr<FJsonObject>& Candidate, const FString& Query, const FString& Intent, const FString& Operator, const FString& ValueType);
	static bool IsHighConfidenceSpawnerCandidate(const TSharedPtr<FJsonObject>& Candidate, const FString& Query, const FString& Intent, const FString& Operator, const FString& ValueType, int32 Score, FString& OutReason);
	static bool IsUnsupportedInputEventRequest(const FString& Query, const FString& Intent);
	static FString NormalizeResolverText(const FString& Text);
	static void AddUniqueString(TArray<FString>& Strings, const FString& Value);
	static FString JsonObjectToString(const TSharedPtr<FJsonObject>& Object);
	static FString JsonValueToString(const TSharedPtr<FJsonValue>& Value);
	static TSharedPtr<FJsonValue> CloneJsonValue(const TSharedPtr<FJsonValue>& Value);
	static TSharedPtr<FJsonObject> CloneJsonObject(const TSharedPtr<FJsonObject>& Object);

	TSharedPtr<IHttpRouter> Router;
	FHttpRouteHandle RouteHandle;
	uint16 ActivePort = 0;
	bool bRunning = false;
	bool bBlueprintSearchCacheValid = false;
	FString BlueprintSearchCacheKey;
	TArray<TSharedPtr<FJsonValue>> BlueprintSearchCache;
	TArray<TSharedPtr<FJsonValue>> BlueprintSearchCacheFailures;
};
