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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "FpsPlayerController.generated.h"

class UConfirmDialogWidget;
class UHotbarWidget;
class UInputAction;
class UInventoryComponent;
class UInteractionPromptWidget;
class UInventoryWidget;
class UPauseMenuWidget;
class UScreenFadeComponent;
class USettingsMenuWidget;
class USurvivalStatsWidget;
class UUserWidget;
struct FInputActionValue;

/**
 * Controller du joueur. C'est ici que vit l'UI, et pas dans le personnage :
 * le controller survit a la mort du pawn, alors que le personnage non.
 * Si tu creais le HUD dans AFpsPlayer, il disparaitrait a chaque respawn.
 */
UCLASS()
class SURVIVAL_PROJET_API AFpsPlayerController : public APlayerController
{
	GENERATED_BODY()

public:
	AFpsPlayerController();

	/** Ouvre ou ferme l'inventaire. */
	UFUNCTION(BlueprintCallable, Category = "UI")
	void ToggleInventory();

	UFUNCTION(BlueprintPure, Category = "UI")
	bool IsInventoryOpen() const { return bInventoryOpen; }

	/** Ferme le menu de pause et relance le monde. */
	UFUNCTION(BlueprintCallable, Category = "UI|Pause")
	void ResumeGame();

	/** Ouvre la demande de confirmation. Ne quitte rien par elle-meme. */
	UFUNCTION(BlueprintCallable, Category = "UI|Pause")
	void RequestQuitToMainMenu();

	UFUNCTION(BlueprintPure, Category = "UI|Pause")
	bool IsPauseMenuOpen() const { return bPauseMenuOpen; }

	/** Ouvre l'ecran de reglages par-dessus le menu de pause. */
	UFUNCTION(BlueprintCallable, Category = "UI|Reglages")
	void OpenSettings();

protected:
	virtual void BeginPlay() override;
	virtual void OnPossess(APawn* InPawn) override;
	virtual void SetupInputComponent() override;
	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;

	// ------------------------------------------------------------------
	// Fondus
	//
	// La mécanique elle-même vit dans UScreenFadeComponent, partagé avec le
	// menu principal. Ici on ne garde que les durées propres au jeu.
	// La couleur et le WBP_Fade se règlent sur le composant.
	// ------------------------------------------------------------------

	/** Le voile. Assigne-lui ton WBP_Fade dans BP_FpsPlayerController. */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "UI|Fondu")
	TObjectPtr<UScreenFadeComponent> ScreenFade;

	/** Décoche pour démarrer sans fondu, pratique pendant les tests. */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Fondu")
	bool bFadeInOnStart = true;

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Fondu", meta = (ClampMin = "0.1"))
	float StartupFadeDuration = 1.5f;

	/** Durée du fondu au noir quand le joueur meurt. */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Fondu", meta = (ClampMin = "0.1"))
	float DeathFadeDuration = 1.f;

	/**
	 * Temps total entre la mort et la réapparition.
	 * Doit rester supérieur à DeathFadeDuration, sinon le joueur réapparaît
	 * avant que l'écran soit entièrement noir.
	 */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Fondu", meta = (ClampMin = "0.1"))
	float RespawnDelay = 3.f;

	/**
	 * Ouverture de l'inventaire, valeur Digital (bool).
	 * L'input d'interface vit sur le controller et non sur le pawn : ouvrir
	 * son sac doit rester possible meme sans corps a piloter.
	 */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
	TObjectPtr<UInputAction> ToggleInventoryAction;

	/**
	 * Jette l'objet survole, valeur Digital (bool). Ctrl enfonce = un seul
	 * exemplaire au lieu de la pile entiere.
	 * Sur le controller aussi : le pawn a ses inputs coupes quand l'inventaire
	 * est ouvert, donc un binding sur le pawn ne repondrait jamais.
	 */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
	TObjectPtr<UInputAction> DropItemAction;

	/**
	 * Selection directe d'un slot de la barre rapide, valeur Axis1D.
	 *
	 * Une seule action pour toutes les touches : dans IMC_Default, mappe les
	 * touches 1 a 6 sur cette action et donne a chacune un modificateur
	 * Scalar different (1, 2, 3...). Le handler lit la valeur et en deduit
	 * le slot. Six actions separees seraient six assets a maintenir.
	 */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
	TObjectPtr<UInputAction> HotbarSelectAction;

	/** Molette de souris pour defiler dans la barre, valeur Axis1D. */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
	TObjectPtr<UInputAction> HotbarScrollAction;

	/**
	 * Echap : ferme l'inventaire s'il est ouvert, sinon bascule la pause.
	 *
	 * ATTENTION : coche "Trigger When Paused" sur l'asset IA_Pause. Un jeu en
	 * pause ne fait plus qu'un tick reduit ou seules les actions portant ce
	 * drapeau sont evaluees -- sans lui, on peut mettre en pause mais plus
	 * jamais en sortir au clavier.
	 */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
	TObjectPtr<UInputAction> PauseAction;

	/**
	 * Viseur, affiche en permanence. Widget separe du prompt : ce dernier se
	 * met en Collapsed des qu'on ne vise plus rien, et emporterait le viseur
	 * avec lui s'ils partageaient le meme widget.
	 */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI")
	TSubclassOf<UUserWidget> CrosshairClass;

	/** A assigner dans BP_FpsPlayerController : ton WBP_InteractionPrompt. */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI")
	TSubclassOf<UInteractionPromptWidget> InteractionPromptClass;

	/** Ton WBP_Inventory. */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI")
	TSubclassOf<UInventoryWidget> InventoryClass;

	/** Ton WBP_Hotbar, affiche en permanence. */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI")
	TSubclassOf<UHotbarWidget> HotbarClass;

	/** Ton WBP_SurvivalStats : les trois jauges. */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI")
	TSubclassOf<USurvivalStatsWidget> SurvivalStatsClass;

	/** Ton WBP_PauseMenu. */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Pause")
	TSubclassOf<UPauseMenuWidget> PauseMenuClass;

	/**
	 * Ton WBP_ConfirmDialog, le meme que celui du menu principal. Laisse-le
	 * assigne : sans lui on retourne au menu sans rien demander, et la partie
	 * est perdue sur un clic.
	 */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Pause")
	TSubclassOf<UConfirmDialogWidget> QuitToMenuDialogClass;

	/** La question posee avant d'abandonner la partie. */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Pause")
	FText QuitToMenuMessage;

	/**
	 * Ton WBP_Settings, le meme que celui du menu principal. C'est tout
	 * l'interet de son delegue OnCloseRequested : l'ecran ignore qui l'ouvre.
	 */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Reglages")
	TSubclassOf<USettingsMenuWidget> SettingsMenuClass;

	/**
	 * Ta map de menu principal.
	 *
	 * TSoftObjectPtr comme dans AMainMenuPlayerController : une reference dure
	 * ferait charger la map du menu en meme temps que celle du jeu.
	 */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Pause")
	TSoftObjectPtr<UWorld> MainMenuLevel;

	/** Fondu au noir avant de rendre la main au menu principal. */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Fondu", meta = (ClampMin = "0.1"))
	float QuitToMenuFadeDuration = 1.f;

	UPROPERTY(Transient, BlueprintReadOnly, Category = "UI")
	TObjectPtr<UUserWidget> Crosshair;

	UPROPERTY(Transient, BlueprintReadOnly, Category = "UI")
	TObjectPtr<UInteractionPromptWidget> InteractionPrompt;

	UPROPERTY(Transient, BlueprintReadOnly, Category = "UI")
	TObjectPtr<UInventoryWidget> InventoryWidget;

	UPROPERTY(Transient, BlueprintReadOnly, Category = "UI")
	TObjectPtr<UHotbarWidget> Hotbar;

	UPROPERTY(Transient, BlueprintReadOnly, Category = "UI")
	TObjectPtr<USurvivalStatsWidget> SurvivalStatsWidget;

	UPROPERTY(Transient, BlueprintReadOnly, Category = "UI|Pause")
	TObjectPtr<UPauseMenuWidget> PauseMenu;

	UPROPERTY(Transient, BlueprintReadOnly, Category = "UI|Pause")
	TObjectPtr<UConfirmDialogWidget> QuitToMenuDialog;

	UPROPERTY(Transient, BlueprintReadOnly, Category = "UI|Reglages")
	TObjectPtr<USettingsMenuWidget> SettingsMenu;

private:
	void CreateHudWidgets();

	/**
	 * Echap. Une seule touche pour trois usages, d'ou une priorite explicite :
	 * boite de confirmation, puis inventaire, puis pause. Sans cet ordre on se
	 * retrouve avec l'inventaire et la pause ouverts en meme temps.
	 */
	void HandlePauseInput();

	void OpenPauseMenu();

	/** Oui : fondu au noir, puis retour au menu principal. */
	UFUNCTION()
	void HandleQuitToMenuConfirmed();

	/** Non : on referme la boite et on rend la main au menu de pause. */
	UFUNCTION()
	void HandleQuitToMenuCancelled();

	/** Le fondu est termine : on charge la map du menu, si c'est ce qu'on attendait. */
	UFUNCTION()
	void HandleFadeFinished();

	/** L'ecran de reglages demande a se fermer : on rend la main au menu de pause. */
	UFUNCTION()
	void HandleSettingsCloseRequested();

	/** Jette la pile survolee dans la grille, si l'inventaire est ouvert. */
	void DropHoveredItem();

	void HandleHotbarSelect(const FInputActionValue& Value);
	void HandleHotbarScroll(const FInputActionValue& Value);

	/** Raccourci vers l'inventaire du pawn possede. */
	UInventoryComponent* GetPawnInventory() const;

	/** Branche sur OnDied du pawn possede. */
	UFUNCTION()
	void HandlePawnDied();

	/** Detruit le cadavre et demande un nouveau pawn au GameMode. */
	void RespawnPlayer();

	FTimerHandle RespawnTimerHandle;

	bool bInventoryOpen = false;

	bool bPauseMenuOpen = false;

	/**
	 * La boite de confirmation avale Echap elle-meme quand elle a le focus,
	 * mais un clic ailleurs le lui retire : sans ce booleen, Echap refermerait
	 * alors le menu de pause en laissant la question affichee dans le vide.
	 */
	bool bQuitToMenuDialogOpen = false;

	bool bSettingsOpen = false;

	/** Distingue le fondu de sortie de tous les autres dans HandleFadeFinished. */
	bool bQuittingToMainMenu = false;
};
