// Clean-room implementation for HyperTwist algorithm-language subsystem
// Implemented from governance docs only (Phase 0R-D, Phase 1R, Phase 5R-A)
// Date: 2026-05-15
// Model: Claude (Model B, Bound 1 contribution)

#include "HyperTwistAlgorithm/HyperTwistAlgorithmLibrary.h"
#include "HyperTwistAlgorithm/HyperTwistAlgorithmParser.h"
#include "HyperTwistAlgorithm/HyperTwistAlgorithmSerializer.h"

namespace HyperTwistAlgorithmLibraryInternal
{
	const TCHAR* AlgorithmSubsystemProvenance =
		TEXT("HyperTwist first-party algorithm-language subsystem. ")
		TEXT("Clean-room implementation informed by cubing/alg.js (GPL-3.0-or-later) ")
		TEXT("architectural concepts only. No source code inspection. ")
		TEXT("Implemented 2026-05-15 via Phase 5R-A clean-room workflow.");

	FString NodeTypeToString(EHyperTwistAlgorithmNodeType NodeType)
	{
		switch (NodeType)
		{
		case EHyperTwistAlgorithmNodeType::BlockMove: return TEXT("BlockMove");
		case EHyperTwistAlgorithmNodeType::Group: return TEXT("Group");
		case EHyperTwistAlgorithmNodeType::Commutator: return TEXT("Commutator");
		case EHyperTwistAlgorithmNodeType::Conjugate: return TEXT("Conjugate");
		case EHyperTwistAlgorithmNodeType::Pause: return TEXT("Pause");
		case EHyperTwistAlgorithmNodeType::Newline: return TEXT("Newline");
		case EHyperTwistAlgorithmNodeType::Comment: return TEXT("Comment");
		case EHyperTwistAlgorithmNodeType::Sequence: return TEXT("Sequence");
		default: return TEXT("Unknown");
		}
	}

	FString MoveTypeToString(EHyperTwistAlgorithmMoveType MoveType)
	{
		switch (MoveType)
		{
		case EHyperTwistAlgorithmMoveType::Plain: return TEXT("Plain");
		case EHyperTwistAlgorithmMoveType::InnerSlice: return TEXT("InnerSlice");
		case EHyperTwistAlgorithmMoveType::RangedSlice: return TEXT("RangedSlice");
		case EHyperTwistAlgorithmMoveType::WideMove: return TEXT("WideMove");
		default: return TEXT("Unknown");
		}
	}

	FString CommentTypeToString(const EHyperTwistAlgorithmCommentType CommentType)
	{
		switch (CommentType)
		{
		case EHyperTwistAlgorithmCommentType::Line: return TEXT("Line");
		case EHyperTwistAlgorithmCommentType::Block: return TEXT("Block");
		default: return TEXT("Unknown");
		}
	}

	void AppendNodeDebugRow(const FHyperTwistAlgorithmNode& Node, int32 Index, FString& OutTsv)
	{
		OutTsv.Append(FString::FromInt(Index));
		OutTsv.Append(TEXT("\t"));
		OutTsv.Append(NodeTypeToString(Node.NodeType));
		OutTsv.Append(TEXT("\t"));

		switch (Node.NodeType)
		{
		case EHyperTwistAlgorithmNodeType::BlockMove:
			OutTsv.Append(Node.BlockMove.Family);
			OutTsv.Append(TEXT("\t"));
			OutTsv.Append(FString::FromInt(Node.BlockMove.Amount));
			OutTsv.Append(TEXT("\t"));
			OutTsv.Append(MoveTypeToString(Node.BlockMove.GetCanonicalMoveType()));
			OutTsv.Append(Node.BlockMove.UsesWideSuffix() ? TEXT("+wide") : TEXT(""));
			OutTsv.Append(TEXT("\t"));
			OutTsv.Append(FString::FromInt(Node.BlockMove.GetCanonicalInnerLayer()));
			OutTsv.Append(TEXT("\t"));
			OutTsv.Append(FString::FromInt(Node.BlockMove.GetCanonicalOuterLayer()));
			break;

		case EHyperTwistAlgorithmNodeType::Group:
			OutTsv.Append(TEXT("(...)"));
			OutTsv.Append(TEXT("\t"));
			OutTsv.Append(FString::FromInt(Node.Group.Amount));
			OutTsv.Append(TEXT("\t"));
			OutTsv.Append(FString::FromInt(Node.Group.Inner.Num()));
			OutTsv.Append(TEXT(" nodes"));
			break;

		case EHyperTwistAlgorithmNodeType::Commutator:
			OutTsv.Append(TEXT("[A, B]"));
			OutTsv.Append(TEXT("\t"));
			OutTsv.Append(FString::Printf(
				TEXT("count=%d\t%d nodes in A\t%d nodes in B"),
				Node.Commutator.Amount,
				Node.Commutator.A.Num(),
				Node.Commutator.B.Num()));
			break;

		case EHyperTwistAlgorithmNodeType::Conjugate:
			OutTsv.Append(TEXT("[A: B]"));
			OutTsv.Append(TEXT("\t"));
			OutTsv.Append(FString::Printf(
				TEXT("count=%d\t%d nodes in A\t%d nodes in B"),
				Node.Conjugate.Amount,
				Node.Conjugate.A.Num(),
				Node.Conjugate.B.Num()));
			break;

		case EHyperTwistAlgorithmNodeType::Comment:
			OutTsv.Append(CommentTypeToString(Node.Comment.CommentType));
			OutTsv.Append(TEXT("\t"));
			OutTsv.Append(Node.Comment.CommentText.Replace(TEXT("\t"), TEXT(" ")));
			break;

		default:
			OutTsv.Append(TEXT("-"));
			break;
		}

		OutTsv.Append(TEXT("\n"));
	}
}

bool UHyperTwistAlgorithmLibrary::TryCanonicalizeAlgorithmText(
	const FString& AlgorithmText,
	FString& OutCanonicalText,
	FString& OutErrorMessage,
	int32& OutErrorPosition
)
{
	OutCanonicalText.Empty();
	OutErrorMessage.Empty();
	OutErrorPosition = -1;

	const FHyperTwistAlgorithmParseResult ParseResult =
		UHyperTwistAlgorithmParser::ParseAlgorithm(AlgorithmText);
	if (!ParseResult.bSuccess)
	{
		OutErrorMessage = ParseResult.ErrorMessage;
		OutErrorPosition = ParseResult.ErrorPosition;
		return false;
	}

	OutCanonicalText = UHyperTwistAlgorithmSerializer::SerializeAlgorithm(ParseResult.Sequence);
	return true;
}

bool UHyperTwistAlgorithmLibrary::ValidateRoundTrip(
	const FString& AlgorithmText,
	FString& OutReserializedText,
	bool& bOutStructurallyEqual
)
{
	// Parse original
	FHyperTwistAlgorithmParseResult Result1 = UHyperTwistAlgorithmParser::ParseAlgorithm(AlgorithmText);
	if (!Result1.bSuccess)
	{
		bOutStructurallyEqual = false;
		return false;
	}

	// Serialize
	OutReserializedText = UHyperTwistAlgorithmSerializer::SerializeAlgorithm(Result1.Sequence);

	// Parse reserialized
	FHyperTwistAlgorithmParseResult Result2 = UHyperTwistAlgorithmParser::ParseAlgorithm(OutReserializedText);
	if (!Result2.bSuccess)
	{
		bOutStructurallyEqual = false;
		return false;
	}

	// Compare ASTs
	bOutStructurallyEqual = AreAlgorithmsStructurallyEqual(Result1.Sequence, Result2.Sequence);
	return true;
}

FString UHyperTwistAlgorithmLibrary::BuildAlgorithmDebugTsv(const FHyperTwistAlgorithmSequence& Sequence)
{
	using namespace HyperTwistAlgorithmLibraryInternal;

	FString Output = TEXT("index\tnode_type\tpayload\tamount\tdetails\tlayer_1\tlayer_2\n");

	for (int32 Index = 0; Index < Sequence.Nodes.Num(); ++Index)
	{
		AppendNodeDebugRow(Sequence.Nodes[Index], Index, Output);
	}

	return Output;
}

bool UHyperTwistAlgorithmLibrary::AreAlgorithmsStructurallyEqual(
	const FHyperTwistAlgorithmSequence& A,
	const FHyperTwistAlgorithmSequence& B
)
{
	return A == B;  // Uses the operator== defined in FHyperTwistAlgorithmSequence
}

FString UHyperTwistAlgorithmLibrary::GetAlgorithmSubsystemProvenance()
{
	return HyperTwistAlgorithmLibraryInternal::AlgorithmSubsystemProvenance;
}
