/**
 * Copyright 2022-2025 Theai, Inc. dba Inworld AI
 */

#include "Graph/RuntimeData/InworldGraphRuntimeData_RelationState.h"

#include "Graph/InworldGraph.h"

UInworldGraphRuntimeData_RelationState::UInworldGraphRuntimeData_RelationState()
{
	Key = "Relation";
}

FInworldDataHandle UInworldGraphRuntimeData_RelationState::GetData()
{
	return FInworldData_Struct(GetRelation());
}

void UInworldGraphRuntimeData_RelationState::UpdateRelation(const FInworldRelation& InRelation)
{
	Relation = InRelation;
}

void UInworldGraphRuntimeData_RelationState::UpdateRelation(const FString& TextResponse)
{
	TOptional<FInworldRelation> OptionalRelation = ParseRelationResponse(TextResponse);
	if (OptionalRelation.IsSet())
	{
		FInworldRelation RelationUpdate = OptionalRelation.GetValue();
		Relation.Attraction += RelationUpdate.Attraction;
		Relation.Trust += RelationUpdate.Trust;
		Relation.Respect += RelationUpdate.Respect;
		Relation.Familiar += RelationUpdate.Familiar;
		Relation.Flirtatious += RelationUpdate.Flirtatious;
	}
	UE_LOG(LogInworldGraph, Log, TEXT("Relation state updated: %s (%s)"), *GetRelationshipLabelString(), *Relation.ToString());
}

TOptional<FInworldRelation> UInworldGraphRuntimeData_RelationState::ParseRelationResponse(const FString& TextResponse) const
{
	FInworldRelation Result = FInworldRelation();
	TArray<FString> Lines;
	TextResponse.ParseIntoArrayLines(Lines);

	if (Lines.Num() == 0)
	{
		UE_LOG(LogInworldGraph, Warning,
			TEXT("UInworldGraphRuntimeData_RelationState::ParseRelationResponse - Failed to parse relation response"));
		return TOptional<FInworldRelation>();
	}

	for (const FString& Line : Lines)
	{
		TOptional<TPair<FString, int32>> RelationAttribute = ParseRelationAttribute(Line);
		if (RelationAttribute.IsSet())
		{
			const TPair<FString, int32>& Pair = RelationAttribute.GetValue();
			const FString& Name = Pair.Key;
			int32 Value = Pair.Value;

			if (Name.Equals("trust", ESearchCase::IgnoreCase))
			{
				Result.Trust = Value;
			}
			else if (Name.Equals("respect", ESearchCase::IgnoreCase))
			{
				Result.Respect = Value;
			}
			else if (Name.Equals("familiar", ESearchCase::IgnoreCase))
			{
				Result.Familiar = Value;
			}
			else if (Name.Equals("flirtatious", ESearchCase::IgnoreCase))
			{
				Result.Flirtatious = Value;
			}
			else if (Name.Equals("attraction", ESearchCase::IgnoreCase))
			{
				Result.Attraction = Value;
			}
		}
		else
		{
			UE_LOG(LogInworldGraph, Warning,
				TEXT("UInworldGraphRuntimeData_RelationState::ParseRelationResponse - "
					 "Failed to parse relation response value for: %s"),
				*Line);
			return TOptional<FInworldRelation>();
		}
	}

	return Result;
}

TOptional<TPair<FString, int32>> UInworldGraphRuntimeData_RelationState::ParseRelationAttribute(const FString& Line) const
{
	FString Trimmed = Line.TrimStartAndEnd();
	if (Trimmed.IsEmpty() || Trimmed[0] != '-')
	{
		return TOptional<TPair<FString, int32>>();
	}

	int32 ColonPos;
	if (!Trimmed.FindChar(':', ColonPos))
	{
		return TOptional<TPair<FString, int32>>();
	}

	FString Name = Trimmed.Mid(1, ColonPos - 1).TrimStartAndEnd();
	FString ValueStr = Trimmed.Mid(ColonPos + 1).TrimStartAndEnd();

	if (ValueStr.IsNumeric())
	{
		return TOptional(TPair<FString, int32>(Name, FCString::Atoi(*ValueStr)));
	}
	return TOptional<TPair<FString, int32>>();
}
