// Clean-room implementation for HyperTwist algorithm-language subsystem
// Implemented from governance docs only (Phase 0R-D, Phase 1R, Phase 5R-A)
// Date: 2026-05-16
// Bound 4 - keyboard mapping helpers

#include "HyperTwistAlgorithm/HyperTwistAlgorithmKeyboard.h"

#include "HyperTwistAlgorithm/HyperTwistAlgorithmSerializer.h"

namespace HyperTwistAlgorithmKeyboardInternal
{
	const TCHAR* DefaultKeyboardProfileName = TEXT("classic-wca-keyboard/v1");

	FHyperTwistAlgorithmBlockMove MakeMove(
		const TCHAR* Family,
		const int32 Amount,
		const bool bIsWide = false,
		const EHyperTwistAlgorithmMoveType MoveType = EHyperTwistAlgorithmMoveType::Plain,
		const int32 InnerLayer = 0,
		const int32 OuterLayer = 0)
	{
		FHyperTwistAlgorithmBlockMove Move;
		Move.Family = Family;
		Move.Amount = Amount;
		Move.MoveType = MoveType;
		Move.bIsWide = bIsWide;
		Move.InnerLayer = InnerLayer;
		Move.OuterLayer = OuterLayer;
		return Move;
	}

	FHyperTwistAlgorithmKeyboardBinding MakeBinding(
		const FKey& Key,
		const FHyperTwistAlgorithmBlockMove& Move,
		const bool bRequiresShift = false,
		const bool bRequiresNoShift = false)
	{
		FHyperTwistAlgorithmKeyboardBinding Binding;
		Binding.Key = Key;
		Binding.Move = Move;
		Binding.bRequiresShift = bRequiresShift;
		Binding.bRequiresNoShift = bRequiresNoShift;
		return Binding;
	}

	FString SerializeMove(const FHyperTwistAlgorithmBlockMove& Move)
	{
		FHyperTwistAlgorithmNode Node;
		Node.NodeType = EHyperTwistAlgorithmNodeType::BlockMove;
		Node.BlockMove = Move;

		FHyperTwistAlgorithmSequence Sequence;
		Sequence.Nodes.Add(Node);
		return UHyperTwistAlgorithmSerializer::SerializeAlgorithm(Sequence);
	}

	bool EventUsesSuppressedModifier(
		const FHyperTwistAlgorithmKeyboardEvent& KeyboardEvent,
		const FHyperTwistAlgorithmKeyboardPolicy& Policy)
	{
		return (Policy.bSuppressCtrl && KeyboardEvent.bCtrlPressed)
			|| (Policy.bSuppressAlt && KeyboardEvent.bAltPressed)
			|| (Policy.bSuppressMeta && KeyboardEvent.bMetaPressed);
	}

	bool BindingMatchesEvent(
		const FHyperTwistAlgorithmKeyboardBinding& Binding,
		const FHyperTwistAlgorithmKeyboardEvent& KeyboardEvent)
	{
		if (!Binding.Key.IsValid() || Binding.Key != KeyboardEvent.Key)
		{
			return false;
		}

		if (Binding.bRequiresShift && !KeyboardEvent.bShiftPressed)
		{
			return false;
		}

		if (Binding.bRequiresNoShift && KeyboardEvent.bShiftPressed)
		{
			return false;
		}

		return true;
	}

	FHyperTwistAlgorithmKeyboardMappingResult MakeUnsupportedProfileResult(const FString& ProfileName)
	{
		FHyperTwistAlgorithmKeyboardMappingResult Result;
		Result.Status = EHyperTwistAlgorithmKeyboardMappingStatus::UnsupportedProfile;
		Result.ResolvedProfileName = ProfileName;
		return Result;
	}
}

FString UHyperTwistAlgorithmKeyboardLibrary::GetDefaultKeyboardProfileName()
{
	return HyperTwistAlgorithmKeyboardInternal::DefaultKeyboardProfileName;
}

FHyperTwistAlgorithmKeyboardProfile UHyperTwistAlgorithmKeyboardLibrary::GetClassicWcaKeyboardProfile()
{
	using namespace HyperTwistAlgorithmKeyboardInternal;

	FHyperTwistAlgorithmKeyboardProfile Profile;
	Profile.ProfileName = DefaultKeyboardProfileName;
	Profile.Policy.bSuppressCtrl = true;
	Profile.Policy.bSuppressAlt = true;
	Profile.Policy.bSuppressMeta = true;
	Profile.Policy.bSuppressRepeat = false;
	Profile.Bindings = {
		MakeBinding(EKeys::I, MakeMove(TEXT("R"), 1)),
		MakeBinding(EKeys::K, MakeMove(TEXT("R"), -1)),
		MakeBinding(EKeys::J, MakeMove(TEXT("U"), 1)),
		MakeBinding(EKeys::F, MakeMove(TEXT("U"), -1)),
		MakeBinding(EKeys::H, MakeMove(TEXT("F"), 1)),
		MakeBinding(EKeys::G, MakeMove(TEXT("F"), -1)),
		MakeBinding(EKeys::D, MakeMove(TEXT("L"), 1)),
		MakeBinding(EKeys::E, MakeMove(TEXT("L"), -1)),
		MakeBinding(EKeys::S, MakeMove(TEXT("D"), 1)),
		MakeBinding(EKeys::L, MakeMove(TEXT("D"), -1)),
		MakeBinding(EKeys::W, MakeMove(TEXT("B"), 1)),
		MakeBinding(EKeys::O, MakeMove(TEXT("B"), -1)),
		MakeBinding(EKeys::T, MakeMove(TEXT("x"), 1)),
		MakeBinding(EKeys::Y, MakeMove(TEXT("x"), -1)),
		MakeBinding(EKeys::N, MakeMove(TEXT("y"), 1)),
		MakeBinding(EKeys::B, MakeMove(TEXT("y"), -1)),
		MakeBinding(EKeys::P, MakeMove(TEXT("z"), 1)),
		MakeBinding(EKeys::Q, MakeMove(TEXT("z"), -1))
	};
	return Profile;
}

FHyperTwistAlgorithmKeyboardMappingResult UHyperTwistAlgorithmKeyboardLibrary::MapKeyboardEvent(
	const FHyperTwistAlgorithmKeyboardEvent& KeyboardEvent,
	const FHyperTwistAlgorithmKeyboardProfile& Profile)
{
	using namespace HyperTwistAlgorithmKeyboardInternal;

	FHyperTwistAlgorithmKeyboardMappingResult Result;
	Result.ResolvedProfileName = Profile.ProfileName;

	if (!KeyboardEvent.Key.IsValid())
	{
		return Result;
	}

	if (Profile.Policy.bSuppressRepeat && KeyboardEvent.bIsRepeat)
	{
		Result.Status = EHyperTwistAlgorithmKeyboardMappingStatus::SuppressedByRepeat;
		return Result;
	}

	if (EventUsesSuppressedModifier(KeyboardEvent, Profile.Policy))
	{
		Result.Status = EHyperTwistAlgorithmKeyboardMappingStatus::SuppressedByModifier;
		return Result;
	}

	for (const FHyperTwistAlgorithmKeyboardBinding& Binding : Profile.Bindings)
	{
		if (!BindingMatchesEvent(Binding, KeyboardEvent))
		{
			continue;
		}

		Result.Status = EHyperTwistAlgorithmKeyboardMappingStatus::ProducedMove;
		Result.Move = Binding.Move;
		Result.CanonicalText = SerializeMove(Binding.Move);
		Result.bHasMoveIntent = true;
		return Result;
	}

	return Result;
}

FHyperTwistAlgorithmKeyboardMappingResult UHyperTwistAlgorithmKeyboardLibrary::MapKeyboardEventForProfile(
	const FHyperTwistAlgorithmKeyboardEvent& KeyboardEvent,
	const FString& ProfileName)
{
	if (ProfileName == HyperTwistAlgorithmKeyboardInternal::DefaultKeyboardProfileName)
	{
		return MapKeyboardEvent(KeyboardEvent, GetClassicWcaKeyboardProfile());
	}

	return HyperTwistAlgorithmKeyboardInternal::MakeUnsupportedProfileResult(ProfileName);
}
