#pragma once

#include "CoreMinimal.h"
#include "Subsystems/WorldSubsystem.h"
#include "ZMMOEntityTypes.h"
#include "ZMMOWorldSubsystem.generated.h"

class AActor;
class AZMMOPlayerCharacter;
class AZMMOPlayerProxy;
class UZeusNetworkSubsystem;

/**
 *  UZMMOWorldSubsystem
 *
 *  Subsistema por-mundo que orquestra a aplicacao de pacotes de replicacao
 *  recebidos do servidor (`S_SPAWN_PLAYER`, `S_DESPAWN_PLAYER`,
 *  `S_PLAYER_STATE`) em atores na cena. Mantem um registry
 *  `EntityId -> AActor*` e despacha cada mensagem para o ator correto.
 *
 *  Por que `UWorldSubsystem` (e nao `UGameInstanceSubsystem`)?
 *    - Atores so existem dentro de um `UWorld`. Quando o mapa troca, este
 *      registry e descartado naturalmente — sem leak de ponteiros para
 *      atores do mundo anterior.
 *    - O `UZeusNetworkSubsystem` (per-game-instance) continua dono da
 *      conexao UDP e dos delegates; este subsistema apenas escuta os
 *      delegates e materializa atores na cena atual.
 *
 *  Resolucao de classe por `EZMMOEntityType`:
 *    - `RemoteEntityClasses` e um TMap configuravel (BlueprintReadWrite)
 *      com defaults seguros em `Initialize`. Permite trocar
 *      `AZMMOPlayerProxy` por um BP filho com mesh customizada sem
 *      recompilar C++.
 *
 *  Despawn:
 *    - V0: chama `IZMMOEntityInterface::SetEntityRelevant(false)` (preserva
 *      o ator para futuro pooling).
 *    - V1: pool real por `EntityType`, limites de memoria, expiracao.
 */
UCLASS()
class ZMMO_API UZMMOWorldSubsystem : public UWorldSubsystem
{
	GENERATED_BODY()

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

	/**
	 *  Regista o jogador local no registry. Chamado por `AZMMOPlayerCharacter`
	 *  apos receber o `EntityId` autoritativo do servidor (delegate
	 *  `OnPlayerSpawned` com `bIsLocal=true`).
	 */
	UFUNCTION(BlueprintCallable, Category = "ZMMO|World")
	void RegisterLocalEntity(int64 EntityId, AActor* LocalActor);

	/** Numero de entidades remotas actualmente trackeadas. Util em debug overlays. */
	UFUNCTION(BlueprintPure, Category = "ZMMO|World")
	int32 GetTrackedEntityCount() const { return RemoteEntities.Num(); }

protected:
	/**
	 *  Mapa configuravel de classe a usar por `EZMMOEntityType`. Caso vazio,
	 *  usamos defaults seguros (`AZMMOPlayerProxy` para Player, `AZMMOEntity`
	 *  para Mob/NPC/Object — actualizado quando classes especificas existirem).
	 *
	 *  Pode ser preenchido via Blueprint subclassing ou em runtime.
	 */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "ZMMO|World")
	TMap<EZMMOEntityType, TSubclassOf<AActor>> RemoteEntityClasses;

private:
	UFUNCTION()
	void HandlePlayerSpawned(int32 EntityId, bool bIsLocal, FVector PosCm, float YawDeg, int64 ServerTimeMs);

	UFUNCTION()
	void HandlePlayerDespawned(int32 EntityId);

	UFUNCTION()
	void HandlePlayerStateUpdate(int32 EntityId, int32 InputSeq, FVector PosCm, FVector VelCmS, bool bGrounded, int64 ServerTimeMs);

	UClass* ResolveActorClass(EZMMOEntityType EntityType) const;
	UZeusNetworkSubsystem* ResolveZeusNetworkSubsystem() const;

	/**
	 *  Registry de proxies remotos. Chave = `EntityId` autoritativo do servidor.
	 *  Usamos `TWeakObjectPtr` para nao impedir GC se algo der errado e o ator
	 *  for destruido externamente (ex.: troca de mapa).
	 */
	UPROPERTY()
	TMap<int64, TWeakObjectPtr<AActor>> RemoteEntities;

	/** Cached id do jogador local, para ignorar snapshots dele (cliente solto). */
	int64 LocalEntityId = 0;
};
