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

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "InventoryScreenWidget.generated.h"

class AStorageContainer;
class UButton;
class UCraftingWidget;
class UInventoryComponent;
class UInventoryWidget;
class UTextBlock;
class UWidgetSwitcher;

/**
 * L'onglet visible a change. true = Inventaire, false = Fabrication.
 *
 * L'ecran se contente d'annoncer. Ce que ca implique pour le reste du HUD --
 * masquer la barre rapide, par exemple -- ne le regarde pas : il serait alors
 * un widget reutilisable qui connait la pile de son hote, exactement ce qu'on
 * evite partout ailleurs.
 */
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInventoryScreenTabChanged, bool, bInventoryTabActive);

/**
 * L'ecran que Tab ouvre : une barre d'onglets et deux pages, Inventaire et
 * Fabrication.
 *
 * Il ne contient aucune logique de l'une ni de l'autre. Les pages restent des
 * widgets autonomes -- la grille d'inventaire n'a pas change d'une ligne en
 * devenant une page -- et l'ecran ne fait que les montrer, les rebrancher apres
 * un respawn, et relayer au controller ce dont il a besoin.
 *
 * Classe Abstract : on cree un WBP_InventoryScreen qui en herite.
 */
UCLASS(Abstract)
class EMBERWILD_API UInventoryScreenWidget : public UUserWidget
{
	GENERATED_BODY()

public:
	virtual void NativeConstruct() override;

	/** Rebranche les deux pages sur le pawn possede. A appeler depuis OnPossess. */
	void BindToOwningPawn();

	/**
	 * Index de la case d'inventaire survolee, ou INDEX_NONE.
	 *
	 * Renvoie INDEX_NONE des que l'onglet Fabrication est affiche : sans ca, la
	 * touche "jeter" agirait sur une case invisible, sous le panneau de craft.
	 */
	int32 GetHoveredSlotIndex() const;

	/**
	 * Meme chose, avec l'inventaire auquel la case appartient. Depuis les
	 * coffres, l'index seul ne designe plus rien de facon unique.
	 */
	bool GetHoveredSlot(UInventoryComponent*& OutInventory, int32& OutIndex) const;

	/**
	 * Survol d'une case exterieure a l'ecran -- la barre rapide, qui reste
	 * affichee par-dessus lui. Alimente le panneau de detail de la page
	 * d'inventaire, seul panneau existant.
	 */
	void NotifyExternalSlotHovered(UInventoryComponent* Inventory, int32 SlotIndex, bool bHovered);

	/** Revient sur l'onglet Inventaire. Appele a chaque ouverture par Tab. */
	UFUNCTION(BlueprintCallable, Category = "UI")
	void ShowInventoryTab();

	/** Bascule sur l'onglet Fabrication. Appele par la touche dediee. */
	UFUNCTION(BlueprintCallable, Category = "UI")
	void ShowCraftingTab();

	UPROPERTY(BlueprintAssignable, Category = "UI")
	FOnInventoryScreenTabChanged OnTabChanged;

	// ------------------------------------------------------------------
	// Panneau de coffre
	//
	// Le contenu d'un coffre s'affiche A COTE de la grille du joueur, dans ce
	// meme ecran, et non dans un ecran a part. La raison est du ressenti pur :
	// le sac ne bouge pas d'un pixel entre "j'ouvre mon sac" et "j'ouvre un
	// coffre". Deux ecrans distincts le feraient sauter a chaque fois.
	//
	// Techniquement c'est une deuxieme instance du MEME WBP_Inventory que
	// InventoryPage. Elle ne peut pas vivre a l'interieur de WBP_Inventory :
	// un Widget Blueprint qui se contient lui-meme est une reference
	// circulaire, et UMG refuse de le compiler.
	// ------------------------------------------------------------------

	/** Branche et affiche le panneau de droite. Force l'onglet Inventaire. */
	void ShowStorage(AStorageContainer* Container);

	/** Masque et debranche le panneau. Sans effet s'il est deja cache. */
	void HideStorage();

	UFUNCTION(BlueprintPure, Category = "UI|Storage")
	bool IsStorageVisible() const { return bStorageVisible; }

protected:
	/**
	 * Absorbe ou traite les depots qui ne visent aucune page.
	 * Meme regle que dans la grille : lache hors des cases, l'objet est jete.
	 */
	virtual bool NativeOnDrop(const FGeometry& InGeometry, const FDragDropEvent& InDragDropEvent, UDragDropOperation* InOperation) override;

	UPROPERTY(meta = (BindWidget))
	TObjectPtr<UWidgetSwitcher> TabSwitcher;

	UPROPERTY(meta = (BindWidget))
	TObjectPtr<UButton> InventoryTabButton;

	UPROPERTY(meta = (BindWidget))
	TObjectPtr<UButton> CraftingTabButton;

	/**
	 * Ton WBP_Inventory, pose comme enfant du WidgetSwitcher et renomme
	 * "InventoryPage". Les deux pages sont obligatoires : un ecran a onglets
	 * auquel il manque une page n'a aucun sens, autant que le Blueprint refuse
	 * de compiler.
	 */
	UPROPERTY(meta = (BindWidget))
	TObjectPtr<UInventoryWidget> InventoryPage;

	/** Ton WBP_Crafting, renomme "CraftingPage". */
	UPROPERTY(meta = (BindWidget))
	TObjectPtr<UCraftingWidget> CraftingPage;

	/**
	 * Tout le bloc de droite -- cadre, titre, grille, boutons -- qu'on montre et
	 * qu'on cache d'un bloc.
	 *
	 * BindWidgetOptional et non BindWidget, comme tous les elements de coffre
	 * qui suivent : l'ecran doit rester valide dans un projet ou personne n'a
	 * encore construit ce panneau. Sans ca, ajouter les coffres casserait la
	 * compilation de WBP_InventoryScreen tant que la mise en page n'est pas
	 * faite -- et donc l'inventaire entier.
	 */
	UPROPERTY(meta = (BindWidgetOptional))
	TObjectPtr<UWidget> StoragePanel;

	/** Un deuxieme WBP_Inventory, renomme "StorageGrid". DECOCHE-lui Auto Bind To Pawn. */
	UPROPERTY(meta = (BindWidgetOptional))
	TObjectPtr<UInventoryWidget> StorageGrid;

	/** Nom du coffre ouvert. */
	UPROPERTY(meta = (BindWidgetOptional))
	TObjectPtr<UTextBlock> StorageTitle;

	/** Deverse la grille du sac dans le coffre. La barre rapide n'y passe pas. */
	UPROPERTY(meta = (BindWidgetOptional))
	TObjectPtr<UButton> StoreAllButton;

	/** Vide le coffre dans le sac, dans la limite de la place disponible. */
	UPROPERTY(meta = (BindWidgetOptional))
	TObjectPtr<UButton> TakeAllButton;

private:
	UFUNCTION()
	void HandleStoreAllClicked();

	UFUNCTION()
	void HandleTakeAllClicked();

	/** Inventaire du pawn possede, ou nullptr. */
	UInventoryComponent* GetPlayerInventory() const;

	UFUNCTION()
	void HandleInventoryTabClicked();

	UFUNCTION()
	void HandleCraftingTabClicked();

	/**
	 * Affiche une page et grise son bouton d'onglet.
	 *
	 * On passe le widget et non un index en dur : l'ordre des enfants du
	 * WidgetSwitcher se change d'un glisser dans la Designer, et un 0/1 code ici
	 * inverserait silencieusement les onglets le jour ou ca arrive.
	 */
	void ShowPage(UWidget* Page);

	bool IsInventoryTabActive() const;

	/**
	 * Le panneau de coffre est affiche.
	 *
	 * Tant qu'il l'est, l'onglet Fabrication est grise : fabriquer avec un
	 * coffre ouvert a cote n'a pas de sens tant que ses ressources ne comptent
	 * pas dans les recettes, et laisser le bouton actif inviterait a un clic
	 * dont le resultat serait incomprehensible.
	 */
	bool bStorageVisible = false;

	TWeakObjectPtr<UInventoryComponent> BoundStorage;
};
