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

#pragma once

#include "CoreMinimal.h"
#include "InworldCharacterTypes.h"
#include "UObject/Object.h"

#include "SpeakerRuleDirector.generated.h"

/**
 * @class USpeakerRuleDirector
 * @brief An object that holds a set of speaker rules and manages an active rule.
 * This object is designed to be instantiated and configured on a UInworldConversationGroupComponent.
 */
UCLASS(Blueprintable, BlueprintType, EditInlineNew)
class INWORLDCHARACTER_API USpeakerRuleDirector : public UObject
{
	GENERATED_BODY()

public:
	/**
	 * @brief Activates a specific rule by its ID.
	 * @param RuleID The ID of the rule to activate, as defined in the Rules array.
	 */
	UFUNCTION(BlueprintCallable, Category = "Inworld|Speaker Director")
	void SetActiveRule(FName RuleID);

	/**
	 * @brief Deactivates any active rule, reverting to AI-driven speaker selection.
	 */
	UFUNCTION(BlueprintCallable, Category = "Inworld|Speaker Director")
	void ClearActiveRule();

	/**
	 * @brief Gets the ID of the currently active rule.
	 */
	UFUNCTION(BlueprintPure, Category = "Inworld|Speaker Director")
	FName GetActiveRule() const
	{
		return ActiveRuleID;
	}

	/**
	 * @brief (Internal) Calculates the next speaker based on the active rule.
	 * @param LastSpeakerID The CharacterID of the last character who spoke.
	 * @param ParticipantIDs A list of all valid CharacterIDs in the current conversation.
	 * @return The CharacterID of the next speaker if a rule dictates it, otherwise an empty TOptional.
	 */
	TOptional<FString> GetNextSpeaker(const FString& LastSpeakerID, const TArray<FString>& ParticipantIDs);

protected:
	/**
	 * @brief The library of all rules this director knows about.
	 * Configure this in the Details panel of the UInworldConversationGroupComponent.
	 */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Speaker Rules",
		meta = (ToolTip = "The library of all rules this director knows about."))
	TArray<FSpeakerRule> Rules;

private:
	/** @brief The ID of the rule that is currently active. If NAME_None, AI selection is used. */
	UPROPERTY(Transient)
	FName ActiveRuleID = NAME_None;

	/** The index of the last speaker within the active rule's sequence. Resets to -1 when a new rule is set or cleared. */
	UPROPERTY(Transient)
	int32 CurrentSequenceIndex = INDEX_NONE;
};
