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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Components/BillboardComponent.h"
#include "Components/SceneComponent.h"

#include "MapAmbientSound.generated.h"

// Which ambience the map plays. The game holds the actual MetaSound for each entry, in a
// data asset a mod map cannot reach -- the swap cannot copy an object property, so an
// index is the only thing that can cross. That is not a limitation to work around: it is
// what stops a pak from naming an arbitrary audio asset.
//
// KEEP THE ORDER IDENTICAL to the game's EMapAmbientSoundType
// (Source/VHOLUME/Public/MapAmbientSound.h). The swap maps by integer value, never by
// name, so reordering silently repoints every already-packed map that used a moved entry.
// APPEND ONLY.
UENUM(BlueprintType)
enum class EMapAmbientSoundType : uint8
{
    // Index 0. Game-side this means "use the MetaSound picked by hand in the campaign
    // level", which a mod map has no way to set -- so choosing it here plays nothing.
    // It exists only to hold slot 0 so the campaign's untouched actors keep working.
    Custom     UMETA(Hidden),
    WindOpen   UMETA(DisplayName = "Wind - Open Air"),
    WindCity   UMETA(DisplayName = "Wind - City"),
    WindPipes  UMETA(DisplayName = "Wind - Pipes & Vents"),
    WindIndoor UMETA(DisplayName = "Wind - Indoor / Muffled"),
    Sewers     UMETA(DisplayName = "Sewers"),
    Conapt     UMETA(DisplayName = "Conapt Interior")
};

/**
 * Mapper-facing proxy for the game's ambient sound bed.
 *
 * This is NOT the game's BP_AmbientSound. Place this actor instead in a vanilla-UE
 * mapping project. At map load the shipped game swaps it for BP_AmbientSound, copies
 * these properties across by name, and destroys the proxy. See Docs/SYNC.md for the swap
 * contract, and the game's Docs/CodeNotes.md [MODPROXY-04].
 *
 * **Place exactly one.** The ambience is a bed glued to the listener, not an emitter --
 * the game moves it onto the player every frame. Two of them are not two zones; they are
 * the same sound at double volume, and moving them apart changes nothing. The game
 * enforces this: extras are destroyed unswapped at load. Map Check warns about it here so
 * you find out now rather than after packing a pak.
 *
 * Where you put it does not matter either, for the same reason. Drop it anywhere.
 */
UCLASS(Blueprintable, meta = (DisplayName = "Ambient Sound"))
class VHOLUME_API AMapAmbientSound : public AActor
{
    GENERATED_BODY()

public:
    AMapAmbientSound();

    /** Root scene component. */
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Ambient Sound")
    USceneComponent* Root;

    /** Editor-only icon. */
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Ambient Sound")
    UBillboardComponent* Billboard;

    /** Which ambience this map plays. */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Ambient Sound",
              meta = (ToolTip = "Which ambience this map plays. Place exactly one per map - the ambience follows the player, so a second one only doubles the volume."))
    EMapAmbientSoundType AmbientType;

    /**
     * Offset from the player, in cm. The ambience follows the listener; this shifts it.
     * Leave at zero unless you want the sound to sit above or below the player.
     */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Ambient Sound")
    FVector PositionOffset;

    // Deliberately NOT mirrored from the game's BP_AmbientSound:
    //   MetaSound        - an object property. It cannot cross the swap at all, and
    //                      letting a pak name an audio asset is exactly what AmbientType
    //                      exists to prevent.
    //   SubmixFilter     - the shared ambient filter preset, a game-only asset.
    //   LowPassCurve     - the room-response curve, shared by every ambience.
    //   Enclosure / AudioRoomController / ParkourCharacter - runtime state.

#if WITH_EDITOR
    // Map Check validation. The game silently drops the extras, so without this a mapper
    // who placed two would only find out by packing, playing, and noticing the wrong one
    // survived -- and which one survives is not something they can predict or control.
    virtual void CheckForErrors() override;
#endif
};
