#pragma once

#include "CoreMinimal.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "UI/InGameTypes.h"
#include "UIInGameFlowSubsystem.generated.h"

class UUIInGameScreenSet;
class UUIManagerSubsystem;
class UCommonActivatableWidget;
struct FGameplayTag;

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnZMMOInGameStateChanged, EZMMOInGameUIState, NewState);

/**
 *  Orquestrador da UI in-game. Espelho simetrico do UUIFrontEndFlowSubsystem
 *  (Game/UI/FrontEnd/UIFrontEndFlowSubsystem.h) — o front-end gerencia
 *  Boot/Login/ServerSelect/Lobby; este subsystem gerencia
 *  HUD/StatusWindow/Inventory/SkillTree/EscapeMenu in-world.
 *
 *  UGameInstanceSubsystem pra persistir entre OpenLevel (futuro: trocar
 *  de mapa in-game preserva estado da UI). Inicializa em modo `None`;
 *  caller (`AZMMOPlayerCharacter::HandleLocalSpawnReady`) chama
 *  `StartInGame()` ao confirmar spawn local, que vai pra `Playing`.
 *
 *  Convencao de layer (resolvida internamente):
 *   - Playing                  -> UI.Layer.Game
 *   - StatusWindow/Inventory/
 *     SkillTree/EscapeMenu     -> UI.Layer.GameMenu
 *   - Loading                  -> UI.Layer.Modal
 *
 *  Adicionar nova tela in-game = 3 passos:
 *   1. Adicionar entry em `EZMMOInGameUIState`
 *   2. Adicionar entry no DA_InGameScreenSet (estado -> WBP)
 *   3. (se for em layer custom) adicionar caso em `LayerForState`
 *  Subsystem nao precisa de mudancas.
 */
UCLASS(Config = Game)
class ZMMO_API UUIInGameFlowSubsystem : public UGameInstanceSubsystem
{
	GENERATED_BODY()

public:
	virtual void Initialize(FSubsystemCollectionBase& Collection) override;
	virtual void Deinitialize() override;

	/**
	 *  Ativa a UI in-game. Chamado pelo `AZMMOPlayerCharacter::HandleLocalSpawnReady`
	 *  quando o servidor confirma o spawn local. Garante root layout, limpa
	 *  layers do front-end (Menu/Modal residuais), e vai pra `Playing` (HUD).
	 */
	UFUNCTION(BlueprintCallable, Category = "InGame|UI")
	void StartInGame();

	/** Define o estado top-level. Resolve a tela do DA + push no layer correto. */
	UFUNCTION(BlueprintCallable, Category = "InGame|UI")
	void SetState(EZMMOInGameUIState NewState);

	UFUNCTION(BlueprintPure, Category = "InGame|UI")
	EZMMOInGameUIState GetCurrentState() const { return CurrentState; }

	/**
	 *  Atalho UX: alterna entre `Playing` e a tela passada. Util pra teclas
	 *  de toggle (Alt+A abre/fecha StatusWindow, I abre/fecha Inventory).
	 *  Se ja' estiver em `Screen`, volta pra Playing; senao vai pra `Screen`.
	 */
	UFUNCTION(BlueprintCallable, Category = "InGame|UI")
	void ToggleScreen(EZMMOInGameUIState Screen);

	/** Disparado a cada SetState bem-sucedido. */
	UPROPERTY(BlueprintAssignable, Category = "InGame|UI")
	FOnZMMOInGameStateChanged OnStateChanged;

protected:
	/** DA com o mapa estado->tela. Config em DefaultGame.ini:
	 *      [/Script/ZMMO.UIInGameFlowSubsystem]
	 *      ScreenSetAsset=/Game/ZMMO/UI/InGame/DA_InGameScreenSet.DA_InGameScreenSet
	 */
	UPROPERTY(Config, EditDefaultsOnly, Category = "InGame|UI")
	TSoftObjectPtr<UUIInGameScreenSet> ScreenSetAsset;

private:
	UUIInGameScreenSet* GetScreenSet();
	UUIManagerSubsystem* GetUIManager() const;

	/** Retorna a layer tag onde a tela do estado deve ir. */
	FGameplayTag LayerForState(EZMMOInGameUIState State) const;

	/** Resolve a soft class + push no layer apropriado (async load). */
	void ResolveAndPushScreen(EZMMOInGameUIState State);

	UPROPERTY(Transient)
	EZMMOInGameUIState CurrentState = EZMMOInGameUIState::None;

	UPROPERTY(Transient)
	TObjectPtr<UUIInGameScreenSet> ScreenSet;
};
