#pragma once

#include <pxr/usd/usd/stage.h>
#include <pxr/usd/sdf/layer.h>
#include <pxr/usd/sdf/path.h>
#include <string>
#include <vector>

namespace UsdLayerManager {

class LayerManager;

/// One row for the Render Layer panel. The "Default" entry (isDefault=true)
/// has no backing layer — it represents the unmodified base stage, i.e. every
/// render-layer sublayer muted.
struct RenderLayerInfo {
    std::string          name;
    pxr::SdfLayerHandle  layer;            ///< empty for Default
    std::string          layerIdentifier;  ///< empty for Default; the stable key used everywhere below
    bool                 isActive  = false;
    bool                 isDefault = false;
};

/// Maya-Render-Layers-style layers built on the stage's own sublayer stack.
///
/// Each render layer is a dedicated, file-backed SdfLayer inserted as a
/// sublayer of the stage's root layer (tagged via SdfLayer custom layer data
/// so it's distinguishable from ordinary content sublayers). At most one is
/// ever unmuted ("active") at a time; activating one mutes the rest and
/// repoints the stage's ambient edit target at it, so every existing
/// attribute/transform/shader-connection/material-binding command in the app
/// already lands its edits in the right place with no changes of its own
/// (see docs/adr/0002-render-layer.md).
///
/// Membership (which lights/objects belong to a layer) is stored as a
/// UsdCollectionAPI-compatible relationship (`collection:members:includes`)
/// on a reserved, undefined ("over"-only, never rendered) admin prim inside
/// that layer's own SdfLayer. All reads/writes of it go through raw Sdf-level
/// API rather than UsdCollectionAPI/UsdStage, because muted layers are fully
/// excluded from stage composition — GetPrimAtPath would fail for every
/// layer except the currently-active one, and the panel needs to edit
/// membership on layers that aren't active.
///
/// Switching layers also isolates the viewport to that layer's members: a
/// single top-down traversal authors the minimal set of
/// `visibility = invisible` opinions (into the active layer's own SdfLayer)
/// needed to hide every subtree that contains no member, tracked via that
/// layer's custom layer data so it can be precisely cleared and recomputed
/// without disturbing deliberate visibility overrides.
class RenderLayerManager {
public:
    RenderLayerManager();
    ~RenderLayerManager();

    void SetStage(pxr::UsdStageRefPtr stage);
    void SetLayerManager(LayerManager* mgr) { m_layerManager = mgr; }
    void Refresh();

    /// Default first, then user-created render layers in sublayer order.
    std::vector<RenderLayerInfo> GetRenderLayers() const { return m_layers; }

    /// Creates a new file-backed render layer next to the stage's root layer
    /// (under a ".renderlayers" subdirectory), muted, with an empty member
    /// list. Returns the new layer's identifier, or empty on failure.
    std::string CreateRenderLayer(const std::string& name);
    bool DeleteRenderLayer(const std::string& layerId);
    /// Re-inserts a render layer previously removed by DeleteRenderLayer — its
    /// backing file is left on disk untouched by DeleteRenderLayer, so this
    /// just restores the sublayer reference (always at the top of the stack,
    /// same as a newly-created layer). Used by RenderLayerDeleteCommand::Undo().
    bool RestoreDeletedRenderLayer(const std::string& layerIdentifier);
    bool RenameRenderLayer(const std::string& layerId, const std::string& newName);

    /// Mutes every other render-layer sublayer, unmutes layerId, repoints the
    /// stage's ambient edit target at it, and recomputes viewport isolation.
    /// The first time this is called while Default is active, it remembers
    /// the current edit target so ActivateDefaultLayer() can restore it later
    /// — callers (e.g. an undoable switch command) don't need to manage that
    /// themselves; it's tracked here so it stays correct across Undo/Redo.
    bool ActivateRenderLayer(const std::string& layerId);
    /// Mutes every render-layer sublayer (back to the unmodified base stage)
    /// and restores whatever the edit target was before render-layer mode
    /// was first entered (see ActivateRenderLayer's note).
    void ActivateDefaultLayer();
    std::string GetActiveRenderLayerId() const;
    bool IsDefaultActive() const { return GetActiveRenderLayerId().empty(); }

    /// Sdf-level: the raw, unexpanded `includes` target list. Works
    /// regardless of whether layerId is currently muted.
    std::vector<pxr::SdfPath> GetMembers(const std::string& layerId) const;
    bool AddMember(const std::string& layerId, const pxr::SdfPath& path);
    bool RemoveMember(const std::string& layerId, const pxr::SdfPath& path);

    /// Re-applies whichever render layer was active the last time this stage
    /// was saved (persisted as root-layer custom layer data, since USD mute
    /// state itself is a runtime flag and isn't serialized). Call once after
    /// SetStage(). No-op if nothing was persisted, or the persisted layer no
    /// longer exists.
    void RestorePersistedActiveLayer();

    /// True if this layer carries the "this sublayer is a render layer"
    /// marker RenderLayerManager itself authors on creation. Exposed so
    /// other panels (e.g. StageEditorPanel) that walk the raw sublayer list
    /// can recognize and guard-rail render-layer sublayers without
    /// duplicating the custom-layer-data key.
    static bool IsRenderLayerSublayer(const pxr::SdfLayerHandle& layer);

private:
    void BuildList();
    // LayerManager keeps its own cached sublayer/mute-state snapshot,
    // rebuilt only on its own SetStage()/Refresh()/mutator calls — it has no
    // way to know when RenderLayerManager mutates the root layer's sublayer
    // stack or a layer's mute state directly (bypassing LayerManager's own
    // methods, which every RenderLayerManager mutator below does). Called
    // after every such mutation so StageEditorPanel (backed by LayerManager)
    // doesn't show a stale sublayer list.
    void RefreshLayerManager();
    pxr::SdfLayerHandle FindRenderLayer(const std::string& layerId) const;
    void RecomputeIsolation(const pxr::SdfLayerHandle& layer, const std::string& layerId);
    void ClearAutoHiddenPaths(const pxr::SdfLayerHandle& layer);
    void PersistActiveLayerId(const std::string& layerId);

    pxr::UsdStageRefPtr m_stage;
    LayerManager*        m_layerManager = nullptr;
    std::vector<RenderLayerInfo> m_layers; // [0] is always the Default entry
    // Strong refs so muted render-layer SdfLayers stay alive between
    // Refresh() calls (mirrors LayerManager::m_layerRefs).
    std::vector<pxr::SdfLayerRefPtr> m_layerRefs;
    // Edit target identifier captured the moment render-layer mode is first
    // entered (Default -> any render layer); restored and cleared by
    // ActivateDefaultLayer(). Empty when not currently "in mode".
    std::string m_savedEditTargetIdBeforeMode;
};

} // namespace UsdLayerManager
