#pragma once

#include "CoreMinimal.h"
#include "WingServer.h"
#include "WingHandler.h"
#include "WingFetcher.h"
#include "WingUtils.h"
#include "WingMaterialParameter.h"
#include "Materials/MaterialInstanceConstant.h"
#include "MaterialTypes.h"
#include "Misc/DefaultValueHelper.h"
#include "MaterialInstance_SetParameter.generated.h"


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

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

public:
	UPROPERTY(EditAnywhere, meta=(Description="Target material instance"))
	FString MaterialInstance;

	UPROPERTY(EditAnywhere, meta=(Description="Parameter name to set"))
	FString Parameter;

	UPROPERTY(EditAnywhere, meta=(Description="Parameter association: 'Global', 'Layer', or 'Blend'. Default: 'Global'", Optional))
	FString ParameterAssociation = TEXT("Global");

	UPROPERTY(EditAnywhere, meta=(Description="Layer/blend index (0-based). Only used when ParameterAssociation is 'Layer' or 'Blend'", Optional))
	int32 ParameterLayer = INDEX_NONE;

	UPROPERTY(EditAnywhere, meta=(Description="Value to set (uses Unreal text format, e.g. '0.5' for scalar, '(R=1,G=0,B=0,A=1)' for vector)"))
	FString Value;

	virtual void Register() override
	{
		UWingServer::AddHandler(this,
			TEXT("Set a parameter override on a Material Instance."));
	}
	virtual void Handle() override
	{
		WingFetcher F;
		UMaterialInstanceConstant* MI = F.Asset(MaterialInstance).Cast<UMaterialInstanceConstant>();
		if (!MI) return;

		// Parse the association string.
		EMaterialParameterAssociation Association;
		if (!WingMaterialParameter::ParseMaterialParameterAssociation(ParameterAssociation, Association))
			return;

		// Build the parameter ID to look up.
		FMaterialParameterInfo ParamID(*Parameter, Association, ParameterLayer);

		// Find it in the material's parameter map.
		auto AllParams = WingMaterialParameter::GetMaterialParameters(MI);
		FMaterialParameterMetadata* Found = AllParams.Find(ParamID);
		if (!Found)
		{
			UWingServer::Printf(TEXT("No parameter named '%s' with association=%s layer=%d"),
				*Parameter, *ParameterAssociation, ParameterLayer);
			return;
		}
		if (Found->PrimitiveDataIndex != INDEX_NONE)
		{
			UWingServer::Printf(TEXT("Parameter '%s' uses custom primitive data and cannot be set on a material instance"), *Parameter);
			return;
		}

		EMaterialParameterType Type = Found->Value.Type;

		switch (Type)
		{
		case EMaterialParameterType::Scalar:
		{
			float ScalarValue;
			if (!FDefaultValueHelper::ParseFloat(Value, ScalarValue))
			{
				UWingServer::Printf(TEXT("Failed to parse '%s' as a float"), *Value);
				return;
			}
			MI->SetScalarParameterValueEditorOnly(ParamID, ScalarValue);
			break;
		}
		case EMaterialParameterType::Vector:
		{
			FLinearColor Color;
			if (!Color.InitFromString(Value))
			{
				UWingServer::Printf(TEXT("Failed to parse '%s' as a color/vector (expected format: '(R=1,G=0,B=0,A=1)')"), *Value);
				return;
			}
			MI->SetVectorParameterValueEditorOnly(ParamID, Color);
			break;
		}
		default:
			UWingServer::Printf(TEXT("Parameters of type %d (see EMaterialParameterType) are not implemented"), (int)Type);
			return;
		}
		UWingServer::Printf(TEXT("Set '%s' = %s on %s\n"),
			*Parameter, *Value, *WingUtils::FormatName(MI));
	}
};
