// Copyright (c) 2024 Codemongous LLC. All Rights Reserved.

#include "SSourcifyExpanderArrow.h"

#include "Widgets/Images/SImage.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/SBoxPanel.h"
#include "Widgets/Text/STextBlock.h"

namespace Sourcify
{
	class SConstrainedBox : public SCompoundWidget
	{
	public:
		SLATE_BEGIN_ARGS(SConstrainedBox)
			: _MinWidth()
			, _MaxWidth()
			{
			}
			SLATE_DEFAULT_SLOT(FArguments, Content)
			SLATE_ATTRIBUTE(TOptional<float>, MinWidth)
			SLATE_ATTRIBUTE(TOptional<float>, MaxWidth)
		SLATE_END_ARGS()

		void Construct(const FArguments& InArgs)
		{
			MinWidth = InArgs._MinWidth;
			MaxWidth = InArgs._MaxWidth;

			ChildSlot
				[
					InArgs._Content.Widget
				];
		}
		virtual FVector2D ComputeDesiredSize(float LayoutScaleMultiplier) const override
		{
			const float MinWidthVal = MinWidth.Get().Get(0.0f);
			const float MaxWidthVal = MaxWidth.Get().Get(0.0f);

			if (MinWidthVal == 0.0f && MaxWidthVal == 0.0f)
			{
				return SCompoundWidget::ComputeDesiredSize(LayoutScaleMultiplier);
			}
			else
			{
				FVector2D ChildSize = ChildSlot.GetWidget()->GetDesiredSize();

				double XVal = FMath::Max(MinWidthVal, ChildSize.X);
				if (MaxWidthVal > MinWidthVal)
				{
					XVal = FMath::Min(MaxWidthVal, XVal);
				}

				return FVector2D(XVal, ChildSize.Y);
			}
		}

	private:
		TAttribute< TOptional<float> > MinWidth;
		TAttribute< TOptional<float> > MaxWidth;
	};
}

void SSourcifyExpanderArrow::Construct(const FArguments& InArgs)
{
	ChildContent = InArgs._Content.Widget;

	const bool bIsSubSection = InArgs._bIsSubSection;

	// Sub-sections use a transparent/no-border look with a smaller font
	const FSlateBrush* BorderBrush = bIsSubSection
		? FAppStyle::Get().GetBrush("NoBorder")
		: FAppStyle::Get().GetBrush("DetailsView.CategoryMiddle");
	FSlateColor BorderBgColor = bIsSubSection
		? FSlateColor(FLinearColor::Transparent)
		: FAppStyle::Get().GetSlateColor("Colors.Header");
	FSlateFontInfo FontInfo = bIsSubSection
		? FCoreStyle::GetDefaultFontStyle("Regular", 10)
		: FCoreStyle::GetDefaultFontStyle("Regular", 12);

	ChildSlot
		[
			SNew(SVerticalBox)
				+ SVerticalBox::Slot()
				.AutoHeight()
				[
					SNew(SBorder)
						.BorderImage(BorderBrush)
						.BorderBackgroundColor(BorderBgColor)
						[
							SNew(SHorizontalBox)
								+ SHorizontalBox::Slot()
								.AutoWidth()
								.Padding(0.f,0.f,2.f,0.f)
								[
									SNew(Sourcify::SConstrainedBox)
										.MinWidth(12.0f)
										.Visibility(this, &SSourcifyExpanderArrow::GetExpanderVisibility)
										[
											SAssignNew(ExpanderArrow, SButton)
												.ButtonStyle(FCoreStyle::Get(), "NoBorder")
												.VAlign(VAlign_Center)
												.HAlign(HAlign_Left)
												.ClickMethod(EButtonClickMethod::MouseDown)
												.OnClicked(this, &SSourcifyExpanderArrow::OnExpanderClicked)
												.ContentPadding(0.0f)
												.IsFocusable(false)
												[
													SNew(SImage)
														.Image(this, &SSourcifyExpanderArrow::GetExpanderImage)
														.ColorAndOpacity(FSlateColor::UseSubduedForeground())
												]
										]
								]
								+ SHorizontalBox::Slot()
								.FillWidth(1.0f)
								[
									SNew(STextBlock)
										.Text(FText::FromString(InArgs._ArrowText))
									.Font(FontInfo)
										.ColorAndOpacity(FLinearColor::White)
								]
						]
				]
				+ SVerticalBox::Slot()
				.AutoHeight()
				[
					ChildContent.ToSharedRef()
				]
		];
}

EVisibility SSourcifyExpanderArrow::GetExpanderVisibility() const
{
	return EVisibility::Visible;
}

const FSlateBrush* SSourcifyExpanderArrow::GetExpanderImage() const
{
	FName ResourceName;
	if (ExpansionState == EExpansionState::Expanded)
	{
		if (ExpanderArrow->IsHovered())
		{
			static const FName ExpandedHoveredName = "TreeArrow_Expanded_Hovered";
			ResourceName = ExpandedHoveredName;
		}
		else
		{
			static const FName ExpandedName = "TreeArrow_Expanded";
			ResourceName = ExpandedName;
		}
	}
	else
	{
		if (ExpanderArrow->IsHovered())
		{
			static const FName CollapsedHoveredName = "TreeArrow_Collapsed_Hovered";
			ResourceName = CollapsedHoveredName;
		}
		else
		{
			static const FName CollapsedName = "TreeArrow_Collapsed";
			ResourceName = CollapsedName;
		}
	}

	return FAppStyle::Get().GetBrush(ResourceName);
}

FReply SSourcifyExpanderArrow::OnExpanderClicked()
{
	ExpansionState = ExpansionState == EExpansionState::Expanded ? EExpansionState::Collapsed : EExpansionState::Expanded;

	if (ExpansionState == EExpansionState::Expanded)
	{
		ChildContent->SetVisibility(EVisibility::Visible);
	}
	else
	{
		ChildContent->SetVisibility(EVisibility::Collapsed);
	}

	return FReply::Handled();
}