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

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "CraftingRecipeDataAsset.h"
#include "CraftingWidget.generated.h"

class UButton;
class UCraftingComponent;
class UCraftingIngredientRowWidget;
class UCraftingRecipeSlotWidget;
class UImage;
class UInventoryComponent;
class UPanelWidget;
class UTextBlock;
class UUniformGridPanel;

/**
 * La page de fabrication : la grille de recettes a gauche, le detail de la
 * recette choisie a droite.
 *
 * Elle ne calcule rien. UCraftingComponent lui dit quelles recettes afficher,
 * lesquelles sont realisables, et fabrique quand on clique. Elle s'abonne a
 * l'inventaire et aux postes accessibles pour se rafraichir -- jamais de Tick
 * pour relire un etat.
 */
UCLASS(Abstract)
class EMBERWILD_API UCraftingWidget : public UUserWidget
{
	GENERATED_BODY()

public:
	virtual void NativeConstruct() override;
	virtual void NativeDestruct() override;

	/**
	 * (Re)branche la page sur le pawn actuellement possede.
	 * Indispensable apres un respawn : le nouveau pawn a de nouveaux composants,
	 * et les anciens abonnements pointeraient vers des objets detruits.
	 */
	void BindToOwningPawn();

	/** Relit la liste, l'etat de chaque case et le panneau de detail. */
	UFUNCTION(BlueprintCallable, Category = "Crafting")
	void Refresh();

	/** Appele par une case quand on clique dessus. */
	void NotifyRecipeClicked(UCraftingRecipeDataAsset* InRecipe);

	/**
	 * Restreint l'affichage a un seul poste. Count = tout ce qui est accessible.
	 * Purement visuel : ce filtre ne peut jamais rendre une recette realisable.
	 */
	UFUNCTION(BlueprintCallable, Category = "Crafting")
	void SetStationFilter(ECraftingStation InFilter);

protected:
	/** A nommer exactement "RecipeGrid" dans le Widget Blueprint. */
	UPROPERTY(meta = (BindWidget))
	TObjectPtr<UUniformGridPanel> RecipeGrid;

	/** L'icone du resultat, dans le panneau de droite. */
	UPROPERTY(meta = (BindWidget))
	TObjectPtr<UImage> ResultIcon;

	UPROPERTY(meta = (BindWidget))
	TObjectPtr<UTextBlock> ResultNameText;

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

	/** Facultatif : la description de l'objet produit. */
	UPROPERTY(meta = (BindWidgetOptional))
	TObjectPtr<UTextBlock> ResultDescriptionText;

	/** Facultatif : "x2" quand la recette produit plusieurs exemplaires. Masque sinon. */
	UPROPERTY(meta = (BindWidgetOptional))
	TObjectPtr<UTextBlock> ResultQuantityText;

	/**
	 * Facultatif : le panneau de droite dans son ensemble. Masque tant qu'aucune
	 * recette n'est choisie, pour ne pas afficher un cadre vide au premier
	 * affichage.
	 */
	UPROPERTY(meta = (BindWidgetOptional))
	TObjectPtr<UWidget> DetailsPanel;

	/** Facultatif : message affiche quand aucune recette n'est disponible ici. */
	UPROPERTY(meta = (BindWidgetOptional))
	TObjectPtr<UWidget> EmptyGridMessage;

	/**
	 * Le conteneur des lignes de cout. Declare en UPanelWidget et non en
	 * UVerticalBox : ca laisse le choix d'un Wrap Box ou d'un Grid Panel dans le
	 * Blueprint sans toucher au C++, puisqu'on ne fait qu'y ajouter des enfants.
	 */
	UPROPERTY(meta = (BindWidgetOptional))
	TObjectPtr<UPanelWidget> IngredientList;

	/** Ton WBP_RecipeSlot. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Crafting")
	TSubclassOf<UCraftingRecipeSlotWidget> RecipeSlotClass;

	/** Ton WBP_IngredientRow. Sans elle, la liste de cout reste vide. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Crafting")
	TSubclassOf<UCraftingIngredientRowWidget> IngredientRowClass;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Crafting", meta = (ClampMin = "1"))
	int32 ColumnCount = 5;

private:
	UFUNCTION()
	void HandleInventoryChanged();

	UFUNCTION()
	void HandleStationsChanged();

	UFUNCTION()
	void HandleCraftClicked();

	/** Recree les cases uniquement si la liste affichee a change. */
	void RebuildGrid(const TArray<UCraftingRecipeDataAsset*>& NewRecipes);

	/** Pousse l'etat realisable/non a chaque case et met a jour le panneau. */
	void RefreshStates();

	void RefreshDetails();

	/**
	 * Remplit la liste de cout de la recette choisie.
	 *
	 * Les lignes sont RECYCLEES et non recreees : cette fonction repasse a
	 * chaque changement d'inventaire, donc a chaque ramassage. Detruire puis
	 * reconstruire trois widgets par branche ramassee serait du gaspillage.
	 */
	void RefreshIngredients();

	UCraftingComponent* ResolveCrafting() const;

	/** Detache les deux abonnements. Appele avant de rebrancher, et a la destruction. */
	void UnbindDelegates();

	TWeakObjectPtr<UCraftingComponent> BoundCrafting;

	TWeakObjectPtr<UInventoryComponent> BoundInventory;

	UPROPERTY(Transient)
	TObjectPtr<UCraftingRecipeDataAsset> SelectedRecipe;

	/** UPROPERTY obligatoire : sans ca le GC collecterait les cases. */
	UPROPERTY(Transient)
	TArray<TObjectPtr<UCraftingRecipeSlotWidget>> RecipeSlots;

	UPROPERTY(Transient)
	TArray<TObjectPtr<UCraftingIngredientRowWidget>> IngredientRows;

	ECraftingStation StationFilter = ECraftingStation::Count;
};
