// Fill out your copyright notice in the Description page of Project Settings.


#include "HotbarWidget.h"

#include "Components/HorizontalBox.h"
#include "Components/HorizontalBoxSlot.h"
#include "FpsPlayer.h"
#include "GameFramework/PlayerController.h"
#include "InventoryComponent.h"
#include "InventorySlotWidget.h"

void UHotbarWidget::NativeConstruct()
{
	Super::NativeConstruct();

	BindToOwningPawn();
}

void UHotbarWidget::BindToOwningPawn()
{
	UInventoryComponent* NewInventory = ResolveInventory();
	if (BoundInventory.Get() == NewInventory)
	{
		return;
	}

	if (BoundInventory.IsValid())
	{
		BoundInventory->OnInventoryChanged.RemoveDynamic(this, &UHotbarWidget::HandleInventoryChanged);
		BoundInventory->OnSelectedHotbarSlotChanged.RemoveDynamic(this, &UHotbarWidget::HandleSelectionChanged);
	}

	BoundInventory = NewInventory;

	if (BoundInventory.IsValid())
	{
		BoundInventory->OnInventoryChanged.AddDynamic(this, &UHotbarWidget::HandleInventoryChanged);
		BoundInventory->OnSelectedHotbarSlotChanged.AddDynamic(this, &UHotbarWidget::HandleSelectionChanged);
	}
	else
	{
		UE_LOG(LogTemp, Warning, TEXT("UHotbarWidget : aucun UInventoryComponent trouve sur le pawn possede."));
	}

	// Les cases memorisent l'ancien composant : on les recree.
	for (UInventorySlotWidget* SlotWidget : SlotWidgets)
	{
		if (SlotWidget)
		{
			SlotWidget->RemoveFromParent();
		}
	}
	SlotWidgets.Reset();

	Refresh();
}

void UHotbarWidget::NativeDestruct()
{
	if (BoundInventory.IsValid())
	{
		BoundInventory->OnInventoryChanged.RemoveDynamic(this, &UHotbarWidget::HandleInventoryChanged);
		BoundInventory->OnSelectedHotbarSlotChanged.RemoveDynamic(this, &UHotbarWidget::HandleSelectionChanged);
	}
	BoundInventory.Reset();

	Super::NativeDestruct();
}

UInventoryComponent* UHotbarWidget::ResolveInventory() const
{
	const APlayerController* OwningController = GetOwningPlayer();
	AFpsPlayer* Player = OwningController ? Cast<AFpsPlayer>(OwningController->GetPawn()) : nullptr;
	return Player ? Player->GetInventoryComponent() : nullptr;
}

void UHotbarWidget::HandleInventoryChanged()
{
	Refresh();
}

void UHotbarWidget::SetQuickTransferTarget(UInventoryComponent* InTarget)
{
	QuickTransferTarget = InTarget;

	for (UInventorySlotWidget* SlotWidget : SlotWidgets)
	{
		if (SlotWidget)
		{
			SlotWidget->SetQuickTransferTarget(InTarget);
		}
	}
}

void UHotbarWidget::HandleSelectionChanged(int32 NewIndex)
{
	// Seule la surbrillance bouge : inutile de repousser tout le contenu.
	for (int32 Index = 0; Index < SlotWidgets.Num(); ++Index)
	{
		if (SlotWidgets[Index])
		{
			SlotWidgets[Index]->SetSelected(Index == NewIndex);
		}
	}
}

void UHotbarWidget::HandleSlotHovered(int32 SlotIndex, bool bHovered)
{
	OnSlotHovered.Broadcast(BoundInventory.Get(), SlotIndex, bHovered);
}

void UHotbarWidget::Refresh()
{
	if (!SlotContainer)
	{
		UE_LOG(LogTemp, Warning, TEXT("UHotbarWidget::Refresh : SlotContainer est nul. Le widget nomme 'SlotContainer' manque dans le Blueprint."));
		return;
	}

	if (!BoundInventory.IsValid())
	{
		return;
	}

	const TArray<FInventorySlot>& Slots = BoundInventory->GetSlots();
	const int32 Count = BoundInventory->GetHotbarSlotCount();

	RebuildSlots(Count);

	const int32 Selected = BoundInventory->GetSelectedHotbarIndex();
	for (int32 Index = 0; Index < SlotWidgets.Num(); ++Index)
	{
		if (!SlotWidgets[Index] || !Slots.IsValidIndex(Index))
		{
			continue;
		}

		SlotWidgets[Index]->SetSlot(Slots[Index]);
		SlotWidgets[Index]->SetSelected(Index == Selected);
	}
}

void UHotbarWidget::RebuildSlots(int32 DesiredCount)
{
	if (SlotWidgets.Num() == DesiredCount)
	{
		return;
	}

	if (!SlotWidgetClass)
	{
		UE_LOG(LogTemp, Warning, TEXT("UHotbarWidget : SlotWidgetClass n'est pas assignee, la barre restera vide."));
		return;
	}

	while (SlotWidgets.Num() > DesiredCount)
	{
		const int32 Last = SlotWidgets.Num() - 1;
		if (SlotWidgets[Last])
		{
			SlotWidgets[Last]->RemoveFromParent();
		}
		SlotWidgets.RemoveAt(Last);
	}

	while (SlotWidgets.Num() < DesiredCount)
	{
		UInventorySlotWidget* NewSlot = CreateWidget<UInventorySlotWidget>(this, SlotWidgetClass);
		if (!NewSlot)
		{
			UE_LOG(LogTemp, Error, TEXT("UHotbarWidget : impossible de creer une case a partir de %s. Recompile ce Widget Blueprint."),
				*GetNameSafe(SlotWidgetClass));
			break;
		}

		const int32 Index = SlotWidgets.Num();

		// Meme indexation que la grille : la case 0 de la barre EST le slot 0
		// de l'inventaire. C'est ce qui rend le glisser-deposer entre les deux
		// gratuit -- ils manipulent le meme tableau.
		NewSlot->InitSlot(BoundInventory.Get(), Index);
		NewSlot->OnHoverChanged.AddDynamic(this, &UHotbarWidget::HandleSlotHovered);
		NewSlot->SetQuickTransferTarget(QuickTransferTarget.Get());

		if (UHorizontalBoxSlot* BoxSlot = SlotContainer->AddChildToHorizontalBox(NewSlot))
		{
			BoxSlot->SetPadding(FMargin(SlotPadding));
		}

		SlotWidgets.Add(NewSlot);
	}
}
