#include "HyperTwistUX/HyperTwistFourDimensionalHUDWidget.h"

#include "Blueprint/WidgetTree.h"
#include "Components/Border.h"
#include "Components/Button.h"
#include "Components/ButtonSlot.h"
#include "Components/HorizontalBox.h"
#include "Components/HorizontalBoxSlot.h"
#include "Components/Overlay.h"
#include "Components/OverlaySlot.h"
#include "Components/SizeBox.h"
#include "Components/TextBlock.h"
#include "Components/VerticalBox.h"
#include "Components/VerticalBoxSlot.h"

namespace HyperTwistFourDimensionalHudWidgetInternal
{
	const FLinearColor PanelColor(0.012f, 0.026f, 0.043f, 0.94f);
	const FLinearColor CardColor(0.035f, 0.070f, 0.095f, 0.98f);
	const FLinearColor AccentColor(0.10f, 0.92f, 0.80f, 1.0f);
	const FLinearColor WarmColor(1.0f, 0.63f, 0.24f, 1.0f);
	const FLinearColor TextColor(0.93f, 0.97f, 1.0f, 1.0f);
	const FLinearColor MutedColor(0.62f, 0.72f, 0.80f, 1.0f);
}

UHyperTwistFourDimensionalHUDWidget::UHyperTwistFourDimensionalHUDWidget(
	const FObjectInitializer& ObjectInitializer
)
	: Super(ObjectInitializer)
{
	SetIsFocusable(false);
}

TSharedRef<SWidget> UHyperTwistFourDimensionalHUDWidget::RebuildWidget()
{
	Initialize();
	EnsureWidgetTreeBuilt();
	return Super::RebuildWidget();
}

bool UHyperTwistFourDimensionalHUDWidget::PrepareHudSurface()
{
	EnsureWidgetTreeBuilt();
	return IsHudSurfaceReady();
}

bool UHyperTwistFourDimensionalHUDWidget::IsHudSurfaceReady() const
{
	return WidgetTree != nullptr
		&& WidgetTree->RootWidget != nullptr
		&& TitleText != nullptr
		&& StateText != nullptr
		&& SelectionText != nullptr
		&& PersistenceText != nullptr
		&& SelectionActionRow != nullptr
		&& TurnActionRow != nullptr
		&& ScrambleActionRow != nullptr;
}

void UHyperTwistFourDimensionalHUDWidget::ConfigureSurface(
	const FString& Title,
	const FString& StateSummary,
	const FString& SelectionSummary,
	const FString& LastAction,
	const FString& PersistenceSummary,
	const bool bCellFirstMode
)
{
	EnsureWidgetTreeBuilt();
	if (TitleText != nullptr)
	{
		TitleText->SetText(FText::FromString(Title));
	}
	if (StateText != nullptr)
	{
		StateText->SetText(FText::FromString(StateSummary));
		StateText->SetColorAndOpacity(FSlateColor(
			StateSummary.StartsWith(TEXT("SOLVED"))
				? HyperTwistFourDimensionalHudWidgetInternal::AccentColor
				: HyperTwistFourDimensionalHudWidgetInternal::TextColor));
	}
	if (SelectionText != nullptr)
	{
		SelectionText->SetText(FText::FromString(SelectionSummary));
	}
	if (LastActionText != nullptr)
	{
		LastActionText->SetText(FText::FromString(
			LastAction.IsEmpty()
				? TEXT("Last action: ready")
				: FString::Printf(TEXT("Last action: %s"), *LastAction)));
	}
	if (PersistenceText != nullptr)
	{
		PersistenceText->SetText(FText::FromString(
			FString::Printf(TEXT("Session: %s"), *PersistenceSummary)));
	}
	if (GuidanceText != nullptr)
	{
		GuidanceText->SetText(FText::FromString(
			bCellFirstMode
				? TEXT("Left click turns a cell clockwise; right click turns it counter-clockwise. Shift + right drag or middle drag orbits. Wheel zooms.")
				: TEXT("X/Y/Z/W selects an axis; 1-6 or [ ] selects a layer; Q/E selects a plane; comma/period turns. Shift + right drag or middle drag orbits.")));
	}
	if (SelectionActionRow != nullptr)
	{
		SelectionActionRow->SetVisibility(
			bCellFirstMode ? ESlateVisibility::Collapsed : ESlateVisibility::Visible);
	}
	if (TurnActionRow != nullptr)
	{
		TurnActionRow->SetVisibility(
			bCellFirstMode ? ESlateVisibility::Collapsed : ESlateVisibility::Visible);
	}
	if (ScrambleActionRow != nullptr)
	{
		ScrambleActionRow->SetVisibility(ESlateVisibility::Visible);
	}
	if (ShellButton != nullptr)
	{
		ShellButton->SetVisibility(
			bCellFirstMode ? ESlateVisibility::Collapsed : ESlateVisibility::Visible);
	}
}

void UHyperTwistFourDimensionalHUDWidget::EnsureWidgetTreeBuilt()
{
	using namespace HyperTwistFourDimensionalHudWidgetInternal;
	if (WidgetTree == nullptr || WidgetTree->RootWidget != nullptr)
	{
		return;
	}

	UOverlay* Root = WidgetTree->ConstructWidget<UOverlay>(
		UOverlay::StaticClass(),
		TEXT("FourDimensionalHudRoot"));
	Root->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
	WidgetTree->RootWidget = Root;

	USizeBox* PanelSize = WidgetTree->ConstructWidget<USizeBox>(
		USizeBox::StaticClass(),
		TEXT("FourDimensionalHudPanelSize"));
	PanelSize->SetWidthOverride(520.0f);
	if (UOverlaySlot* PanelSlot = Root->AddChildToOverlay(PanelSize))
	{
		PanelSlot->SetHorizontalAlignment(HAlign_Left);
		PanelSlot->SetVerticalAlignment(VAlign_Top);
		PanelSlot->SetPadding(FMargin(20.0f));
	}

	UBorder* Panel = WidgetTree->ConstructWidget<UBorder>(
		UBorder::StaticClass(),
		TEXT("FourDimensionalHudPanel"));
	Panel->SetPadding(FMargin(20.0f));
	Panel->SetBrushColor(PanelColor);
	PanelSize->AddChild(Panel);

	UVerticalBox* Content = WidgetTree->ConstructWidget<UVerticalBox>(
		UVerticalBox::StaticClass(),
		TEXT("FourDimensionalHudContent"));
	Panel->AddChild(Content);

	UTextBlock* Eyebrow = MakeText(
		TEXT("FOUR-DIMENSIONAL PUZZLE LAB"),
		11,
		AccentColor);
	Content->AddChildToVerticalBox(Eyebrow);
	TitleText = MakeText(
		TEXT("4D Cube"),
		27,
		TextColor,
		TEXT("FourDimensionalHudTitle"));
	Content->AddChildToVerticalBox(TitleText);
	StateText = MakeText(
		TEXT("SOLVED"),
		14,
		AccentColor,
		TEXT("FourDimensionalHudState"));
	if (UVerticalBoxSlot* StateSlot = Content->AddChildToVerticalBox(StateText))
	{
		StateSlot->SetPadding(FMargin(0.0f, 8.0f, 0.0f, 0.0f));
	}
	SelectionText = MakeText(
		TEXT("Projection ready"),
		13,
		TextColor,
		TEXT("FourDimensionalHudSelection"));
	Content->AddChildToVerticalBox(SelectionText);
	LastActionText = MakeText(
		TEXT("Last action: ready"),
		12,
		MutedColor,
		TEXT("FourDimensionalHudLastAction"));
	Content->AddChildToVerticalBox(LastActionText);
	PersistenceText = MakeText(
		TEXT("Session: not loaded"),
		12,
		WarmColor,
		TEXT("FourDimensionalHudPersistence"));
	Content->AddChildToVerticalBox(PersistenceText);

	SelectionActionRow = WidgetTree->ConstructWidget<UHorizontalBox>(
		UHorizontalBox::StaticClass(),
		TEXT("FourDimensionalHudSelectionActions"));
	if (UVerticalBoxSlot* RowSlot =
			Content->AddChildToVerticalBox(SelectionActionRow))
	{
		RowSlot->SetPadding(FMargin(0.0f, 14.0f, 0.0f, 4.0f));
	}
	UButton* AxisButton = AddButton(
		SelectionActionRow,
		TEXT("Cycle axis"),
		TEXT("FourDimensionalHudAxisButton"));
	UButton* PreviousLayerButton = AddButton(
		SelectionActionRow,
		TEXT("- Layer"),
		TEXT("FourDimensionalHudPreviousLayerButton"));
	UButton* NextLayerButton = AddButton(
		SelectionActionRow,
		TEXT("+ Layer"),
		TEXT("FourDimensionalHudNextLayerButton"));
	AxisButton->OnClicked.AddDynamic(
		this,
		&UHyperTwistFourDimensionalHUDWidget::HandleCycleAxis);
	PreviousLayerButton->OnClicked.AddDynamic(
		this,
		&UHyperTwistFourDimensionalHUDWidget::HandlePreviousLayer);
	NextLayerButton->OnClicked.AddDynamic(
		this,
		&UHyperTwistFourDimensionalHUDWidget::HandleNextLayer);

	TurnActionRow = WidgetTree->ConstructWidget<UHorizontalBox>(
		UHorizontalBox::StaticClass(),
		TEXT("FourDimensionalHudTurnActions"));
	if (UVerticalBoxSlot* RowSlot = Content->AddChildToVerticalBox(TurnActionRow))
	{
		RowSlot->SetPadding(FMargin(0.0f, 0.0f, 0.0f, 4.0f));
	}
	UButton* PreviousPlaneButton = AddButton(
		TurnActionRow,
		TEXT("- Plane"),
		TEXT("FourDimensionalHudPreviousPlaneButton"));
	UButton* CounterClockwiseButton = AddButton(
		TurnActionRow,
		TEXT("Turn CCW"),
		TEXT("FourDimensionalHudCounterClockwiseButton"));
	UButton* ClockwiseButton = AddButton(
		TurnActionRow,
		TEXT("Turn CW"),
		TEXT("FourDimensionalHudClockwiseButton"),
		true);
	UButton* NextPlaneButton = AddButton(
		TurnActionRow,
		TEXT("+ Plane"),
		TEXT("FourDimensionalHudNextPlaneButton"));
	PreviousPlaneButton->OnClicked.AddDynamic(
		this,
		&UHyperTwistFourDimensionalHUDWidget::HandlePreviousPlane);
	CounterClockwiseButton->OnClicked.AddDynamic(
		this,
		&UHyperTwistFourDimensionalHUDWidget::HandleCounterClockwise);
	ClockwiseButton->OnClicked.AddDynamic(
		this,
		&UHyperTwistFourDimensionalHUDWidget::HandleClockwise);
	NextPlaneButton->OnClicked.AddDynamic(
		this,
		&UHyperTwistFourDimensionalHUDWidget::HandleNextPlane);

	ScrambleActionRow = WidgetTree->ConstructWidget<UHorizontalBox>(
		UHorizontalBox::StaticClass(),
		TEXT("FourDimensionalHudScrambleActions"));
	if (UVerticalBoxSlot* RowSlot = Content->AddChildToVerticalBox(ScrambleActionRow))
	{
		RowSlot->SetPadding(FMargin(0.0f, 14.0f, 0.0f, 4.0f));
	}
	UButton* ScrambleButton = AddButton(
		ScrambleActionRow,
		TEXT("Scramble"),
		TEXT("FourDimensionalHudScrambleButton"),
		true);
	ScrambleButton->OnClicked.AddDynamic(
		this,
		&UHyperTwistFourDimensionalHUDWidget::HandleScramble);

	UHorizontalBox* SessionActions = WidgetTree->ConstructWidget<UHorizontalBox>(
		UHorizontalBox::StaticClass(),
		TEXT("FourDimensionalHudSessionActions"));
	if (UVerticalBoxSlot* RowSlot = Content->AddChildToVerticalBox(SessionActions))
	{
		RowSlot->SetPadding(FMargin(0.0f, 4.0f, 0.0f, 8.0f));
	}
	UButton* ResetButton = AddButton(
		SessionActions,
		TEXT("Reset"),
		TEXT("FourDimensionalHudResetButton"));
	ShellButton = AddButton(
		SessionActions,
		TEXT("Cell shell"),
		TEXT("FourDimensionalHudShellButton"));
	UButton* SaveButton = AddButton(
		SessionActions,
		TEXT("Save"),
		TEXT("FourDimensionalHudSaveButton"));
	UButton* LoadButton = AddButton(
		SessionActions,
		TEXT("Load"),
		TEXT("FourDimensionalHudLoadButton"));
	ResetButton->OnClicked.AddDynamic(
		this,
		&UHyperTwistFourDimensionalHUDWidget::HandleReset);
	ShellButton->OnClicked.AddDynamic(
		this,
		&UHyperTwistFourDimensionalHUDWidget::HandleToggleShell);
	SaveButton->OnClicked.AddDynamic(
		this,
		&UHyperTwistFourDimensionalHUDWidget::HandleSave);
	LoadButton->OnClicked.AddDynamic(
		this,
		&UHyperTwistFourDimensionalHUDWidget::HandleLoad);

	GuidanceText = MakeText(
		TEXT("Select a projection control or use the keyboard."),
		11,
		MutedColor,
		TEXT("FourDimensionalHudGuidance"));
	Content->AddChildToVerticalBox(GuidanceText);
	UTextBlock* GlobalHelp = MakeText(
		TEXT("Esc menu  |  F3 coach  |  F10 library  |  S save  |  L load"),
		10,
		AccentColor);
	if (UVerticalBoxSlot* HelpSlot = Content->AddChildToVerticalBox(GlobalHelp))
	{
		HelpSlot->SetPadding(FMargin(0.0f, 8.0f, 0.0f, 0.0f));
	}
}

UTextBlock* UHyperTwistFourDimensionalHUDWidget::MakeText(
	const FString& Text,
	const int32 FontSize,
	const FLinearColor& Color,
	const FName& Name
)
{
	UTextBlock* TextBlock = WidgetTree->ConstructWidget<UTextBlock>(
		UTextBlock::StaticClass(),
		Name);
	TextBlock->SetText(FText::FromString(Text));
	TextBlock->SetAutoWrapText(true);
	TextBlock->SetColorAndOpacity(FSlateColor(Color));
	FSlateFontInfo Font = TextBlock->GetFont();
	Font.Size = FontSize;
	TextBlock->SetFont(Font);
	return TextBlock;
}

UButton* UHyperTwistFourDimensionalHUDWidget::AddButton(
	UHorizontalBox* Parent,
	const FString& Label,
	const FName& Name,
	const bool bPrimary
)
{
	using namespace HyperTwistFourDimensionalHudWidgetInternal;
	UButton* Button = WidgetTree->ConstructWidget<UButton>(
		UButton::StaticClass(),
		Name);
	Button->SetBackgroundColor(bPrimary ? AccentColor : CardColor);
	UTextBlock* LabelText = MakeText(
		Label,
		11,
		bPrimary ? FLinearColor(0.01f, 0.04f, 0.05f, 1.0f) : TextColor);
	LabelText->SetJustification(ETextJustify::Center);
	Button->AddChild(LabelText);
	if (UButtonSlot* ContentSlot = Cast<UButtonSlot>(LabelText->Slot))
	{
		ContentSlot->SetPadding(FMargin(10.0f, 7.0f));
		ContentSlot->SetHorizontalAlignment(HAlign_Center);
	}
	if (UHorizontalBoxSlot* ButtonSlot = Parent->AddChildToHorizontalBox(Button))
	{
		ButtonSlot->SetPadding(FMargin(2.0f));
		ButtonSlot->SetSize(FSlateChildSize(ESlateSizeRule::Fill));
	}
	return Button;
}

void UHyperTwistFourDimensionalHUDWidget::HandleCycleAxis()
{
	OnCycleAxisRequested.Broadcast();
}

void UHyperTwistFourDimensionalHUDWidget::HandlePreviousLayer()
{
	OnPreviousLayerRequested.Broadcast();
}

void UHyperTwistFourDimensionalHUDWidget::HandleNextLayer()
{
	OnNextLayerRequested.Broadcast();
}

void UHyperTwistFourDimensionalHUDWidget::HandlePreviousPlane()
{
	OnPreviousPlaneRequested.Broadcast();
}

void UHyperTwistFourDimensionalHUDWidget::HandleNextPlane()
{
	OnNextPlaneRequested.Broadcast();
}

void UHyperTwistFourDimensionalHUDWidget::HandleCounterClockwise()
{
	OnCounterClockwiseRequested.Broadcast();
}

void UHyperTwistFourDimensionalHUDWidget::HandleClockwise()
{
	OnClockwiseRequested.Broadcast();
}

void UHyperTwistFourDimensionalHUDWidget::HandleToggleShell()
{
	OnToggleShellRequested.Broadcast();
}

void UHyperTwistFourDimensionalHUDWidget::HandleScramble()
{
	OnScrambleRequested.Broadcast();
}

void UHyperTwistFourDimensionalHUDWidget::HandleReset()
{
	OnResetRequested.Broadcast();
}

void UHyperTwistFourDimensionalHUDWidget::HandleSave()
{
	OnSaveRequested.Broadcast();
}

void UHyperTwistFourDimensionalHUDWidget::HandleLoad()
{
	OnLoadRequested.Broadcast();
}
