// © 2025 Naked People Team. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "Subsystems/WorldSubsystem.h"
#include "SessionManagerSubsystem.h"
#include "SessionLossResolver.generated.h"

/**
 * Broadcast once a loss has been resolved transactionally. The presentation layer
 * (fade / cutscene / teleport) and the time skip live in Blueprint / the future
 * time subsystem and react to this, switching on FinalCause:
 *   - EmbarrassmentMax        → fade to apartment. No time skip.
 *   - EnergyZero              → trudge-home cutscene, then advance one sleep cycle.
 *   - PoliceCapture (!cell)   → fade to apartment.
 *   - PoliceCapture (cell)    → holding-cell cutscene, then fast-forward to next morning.
 *   - SafeReturn              → no special presentation.
 * The C++ side has already applied money / item / wanted changes by the time this fires.
 */
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSessionLossResolvedSignature, ESessionLossCause, FinalCause, bool, bWentToHoldingCell);

/**
 * The single, deterministic owner of "what gets lost" on session end (GDD §4.4).
 * Subscribes to USessionManagerSubsystem::OnSessionEnd and routes every cause
 * through ResolveLoss. Per the architecture rule, no loss-handling logic should
 * live anywhere else.
 */
UCLASS()
class NAKEDDESIRE_API USessionLossResolver : public UWorldSubsystem
{
	GENERATED_BODY()

public:
	virtual void OnWorldBeginPlay(UWorld& InWorld) override;

	// Single entry point for all §4.4 outcomes. Bound to OnSessionEnd; also callable
	// directly (e.g. from a debug command) to exercise a path.
	UFUNCTION(BlueprintCallable, Category = "Session")
	void ResolveLoss(ESessionLossCause Cause);

	// Voluntary sleep at the apartment bed (§4.4 step 2). Not a session-loss cause — the
	// session already ended on entering the apartment — but any clothing left outside is
	// still guaranteed lost. Lives here so ALL "what gets lost" logic stays in one place.
	UFUNCTION(BlueprintCallable, Category = "Session")
	void ResolveSleepLoss();

	UPROPERTY(BlueprintAssignable, Category = "Session")
	FOnSessionLossResolvedSignature OnSessionLossResolved;

	// Teleport the player pawn to the home APlayerStart (preferring one tagged "Home").
	// Called automatically when a loss cutscene finishes; exposed for debug / direct use.
	UFUNCTION(BlueprintCallable, Category = "Session")
	void TeleportPlayerHome();

private:
	// EnergyZero / sleep: every clothing item left outside the apartment is guaranteed lost.
	void LoseAllWorldClothing();

	// §7.7: cleared on police capture. No-op until the Wanted attribute exists (Phase 6).
	void ClearWanted();

	// Plays the configured cutscene for the resolved cause, then teleports the player home
	// on finish. No cutscene authored → teleports immediately. SafeReturn → no presentation.
	void BeginLossPresentation(ESessionLossCause Cause);

	UFUNCTION()
	void HandleLossCutsceneFinished();

	void Autosave() const;
	class UGlobalSaveGameData* GetSave() const;
	class ULossPresentationConfig* GetPresentationConfig() const;

	// §21 tuning placeholder — the police-capture money penalty.
	float PoliceCaptureMoneyPenalty = 200.0f;

	// PlayerStart tag of the home spawn, preferred over an untagged start (GDD §4.4).
	static const FName HomePlayerStartTag;

	// The level-sequence player/actor for the in-flight loss cutscene. Held so they survive
	// GC until OnFinished fires; torn down in HandleLossCutsceneFinished.
	UPROPERTY()
	TObjectPtr<class ULevelSequencePlayer> ActiveLossSequencePlayer;

	UPROPERTY()
	TObjectPtr<class ALevelSequenceActor> ActiveLossSequenceActor;
};