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

#pragma once

#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "ItemDataAsset.generated.h"

class UMaterialInterface;
class UStaticMesh;
class UTexture2D;

/**
 * Definition d'un TYPE d'objet : "Bois", "Pomme", "Corde".
 * Un asset par type, cree dans le Content Browser, edite a la main.
 *
 * C'est l'equivalent exact d'un ScriptableObject Unity : une donnee partagee
 * que tout le monde reference et que personne ne duplique. Cent buches dans
 * le monde pointent toutes vers le meme UItemDataAsset "Bois".
 *
 * Regle a ne jamais enfreindre : ceci decrit ce qu'est un objet, jamais son
 * etat. La quantite, la durabilite, l'usure appartiennent a l'inventaire ou
 * a l'acteur, pas ici -- sinon ramasser une pomme modifierait toutes les
 * pommes du jeu.
 */
UCLASS(BlueprintType)
class SURVIVAL_PROJET_API UItemDataAsset : public UPrimaryDataAsset
{
	GENERATED_BODY()

public:
	/** Identifiant stable, utilise par la sauvegarde et les recettes de craft. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item")
	FName ItemId;

	/** Nom affiche au joueur. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item")
	FText DisplayName;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item", meta = (MultiLine = "true"))
	FText Description;

	/** Icone affichee dans la grille d'inventaire. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item")
	TObjectPtr<UTexture2D> Icon;

	/** Mesh utilise quand l'objet est pose au sol. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item")
	TObjectPtr<UStaticMesh> WorldMesh;

	/**
	 * Materiau force sur le WorldMesh. Vide = celui du mesh.
	 *
	 * Indispensable des qu'un pack partage une geometrie entre plusieurs
	 * aliments : une chaine de cuisson demande un visuel par etape, et sans ca
	 * il faudrait trois meshes distincts la ou un seul suffit avec trois
	 * teintes. N'ecrase que le PREMIER slot de materiau -- un mesh qui en
	 * expose plusieurs garde les autres tels quels.
	 */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item")
	TObjectPtr<UMaterialInterface> WorldMeshMaterial;

	/**
	 * Nombre maximum d'exemplaires par slot.
	 * 1 = ne s'empile pas (outils, armes), 20 = ressource classique.
	 */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item", meta = (ClampMin = "1"))
	int32 MaxStackSize = 1;

	/**
	 * Nombre d'utilisations avant que l'objet soit consomme.
	 * 1 = objet a usage unique. 3 = une canette qu'on boit en trois gorgees.
	 *
	 * Les valeurs de restauration sont appliquees A CHAQUE utilisation, pas
	 * reparties : une canette a 3 usages et 20 de soif rend 20 par gorgee.
	 */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item", meta = (ClampMin = "1"))
	int32 MaxUses = 1;

	/**
	 * Taille de pile reellement applicable.
	 *
	 * Un objet a charges ne s'empile jamais : deux canettes entamees a des
	 * niveaux differents ne peuvent pas partager un slot, il faudrait stocker
	 * deux compteurs dans une seule case. La regle est centralisee ici pour
	 * qu'aucun appelant ne puisse l'oublier.
	 */
	UFUNCTION(BlueprintPure, Category = "Item")
	int32 GetEffectiveMaxStack() const { return MaxUses > 1 ? 1 : FMath::Max(1, MaxStackSize); }

	/**
	 * Pose le mesh et le materiau de l'objet sur un composant.
	 *
	 * Un DataAsset ne devrait pas piloter un composant, mais la regle "mesh plus
	 * materiau optionnel" a deja deux appelants -- l'objet au sol et l'objet sur
	 * le feu -- et en aura d'autres, l'objet en main le premier. La dupliquer
	 * garantit qu'un jour l'un des deux oubliera le materiau.
	 */
	UFUNCTION(BlueprintCallable, Category = "Item")
	void ApplyWorldVisualsTo(class UStaticMeshComponent* Component) const;

	/**
	 * Slots ajoutes a l'inventaire quand cet objet est equipe comme sac.
	 * Laisse a 0 pour tout ce qui n'est pas un contenant.
	 */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Backpack", meta = (ClampMin = "0"))
	int32 BonusInventorySlots = 0;

	// ------------------------------------------------------------------
	// Consommable
	// ------------------------------------------------------------------

	/** Coche pour qu'un clic gauche consomme l'objet et applique ses effets. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Consumable")
	bool bIsConsumable = false;

	/** Faim rendue a la consommation. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Consumable", meta = (EditCondition = "bIsConsumable"))
	float HungerRestore = 0.f;

	/** Soif rendue. Une valeur negative deshydrate -- utile pour l'eau salee. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Consumable", meta = (EditCondition = "bIsConsumable"))
	float ThirstRestore = 0.f;

	/** Vie rendue. Negative pour un aliment avarie ou toxique. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Consumable", meta = (EditCondition = "bIsConsumable"))
	float HealthRestore = 0.f;

	// ------------------------------------------------------------------
	// Cuisson
	//
	// Modele en CHAINE D'OBJETS, sans recette : cuire n'est pas un choix que le
	// joueur fait dans un menu, c'est une propriete de l'objet. "Steak cru"
	// pointe vers "Steak cuit", qui pointe vers "Steak brule". Chaque maillon
	// est un asset complet, donc le changement de mesh sur le feu ne coute pas
	// une ligne : c'est le WorldMesh du maillon suivant.
	//
	// Ce qui n'est PAS ici, et ne doit jamais y venir : le temps deja passe sur
	// le feu. C'est de l'etat, il vit sur ACookingStation. Le mettre dans le
	// DataAsset ferait cuire tous les steaks du monde en meme temps.
	// ------------------------------------------------------------------

	/** Cet objet se transforme quand on le pose sur un feu allume. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Cooking")
	bool bCanBeCooked = false;

	/** Secondes de feu ACTIF necessaires. Un feu eteint met le compteur en pause. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Cooking", meta = (EditCondition = "bCanBeCooked", ClampMin = "0.1", Units = "s"))
	float CookDuration = 20.f;

	/** Ce que l'objet devient une fois cuit. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Cooking", meta = (EditCondition = "bCanBeCooked"))
	TObjectPtr<UItemDataAsset> CookedResult;

	/**
	 * L'objet se degrade s'il reste sur le feu.
	 *
	 * Volontairement independant de bCanBeCooked : un objet peut bruler sans
	 * jamais avoir ete cuisinable (une planche jetee dans les flammes), et un
	 * plat peut rester indefiniment au chaud sans jamais se gacher. Une seule
	 * chaine commune imposerait l'un ou l'autre a tout le monde.
	 *
	 * Si les deux sont coches, la CUISSON passe en premier : c'est le maillon
	 * cuit qui portera bCanBurn pour continuer vers le brule.
	 */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Cooking")
	bool bCanBurn = false;

	/** Secondes de feu actif avant que l'objet se gache. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Cooking", meta = (EditCondition = "bCanBurn", ClampMin = "0.1", Units = "s"))
	float BurnDuration = 40.f;

	/** Ce que l'objet devient une fois brule. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Cooking", meta = (EditCondition = "bCanBurn"))
	TObjectPtr<UItemDataAsset> BurntResult;

	/**
	 * Le feu accepte-t-il cet objet sur un emplacement de cuisson.
	 *
	 * Un maillon final -- le steak brule -- repond non : on ne peut plus le
	 * poser, et il ne fait plus rien s'il est deja la. La regle est centralisee
	 * ici pour que la station n'ait pas a la reconstruire a chaque appel.
	 */
	UFUNCTION(BlueprintPure, Category = "Item|Cooking")
	bool CanBePlacedOnFire() const
	{
		return (bCanBeCooked && CookedResult != nullptr) || (bCanBurn && BurntResult != nullptr);
	}

	// ------------------------------------------------------------------
	// Carburant
	// ------------------------------------------------------------------

	/** Cet objet peut alimenter un feu. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Fuel")
	bool bIsFuel = false;

	/** Secondes de combustion apportees par exemplaire. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Fuel", meta = (EditCondition = "bIsFuel", ClampMin = "1", Units = "s"))
	float FuelDuration = 60.f;

#if WITH_EDITOR
	/**
	 * Une chaine de cuisson mal branchee ne planterait pas : la viande resterait
	 * simplement crue sur le feu, sans rien dire. C'est exactement le genre de
	 * bug qu'on cherche une heure -- autant que l'editeur le refuse a la
	 * sauvegarde.
	 */
	virtual EDataValidationResult IsDataValid(class FDataValidationContext& Context) const override;
#endif
};
