#pragma once

#include "../core/PropertyManager.h"
#include "../core/CommandHistory.h"
#include "../core/commands/TransformCommand.h"
#include "IconManager.h"
#include <pxr/usd/usd/stage.h>
#include <pxr/usd/usd/timeCode.h>
#include <pxr/usd/sdf/path.h>
#include <pxr/base/gf/vec3f.h>
#include <pxr/base/gf/vec3d.h>
#include <pxr/usd/usdGeom/xformCommonAPI.h>
#include <imgui.h>
#include <functional>
#include <string>

namespace UsdLayerManager {

/// Maya Channel Box-style property panel.
/// Displays TRS transform, variant sets, all USD attributes, and relationships
/// for the currently selected prim.
class PropertyPanel {
public:
    PropertyPanel();
    ~PropertyPanel();

    void SetPropertyManager(PropertyManager* manager);
    void SetCommandHistory(CommandHistory* history) { m_commandHistory = history; }
    void SetIconManager(IconManager* icons) { m_iconManager = icons; }
    void SetStage(pxr::UsdStageRefPtr stage);
    void SetSelectedPrimPath(const std::string& path);

    /// displayTime — frame used to read/display attribute values.
    /// editTime    — frame writes are authored at (Default unless Auto-Key).
    void SetTimeCodes(pxr::UsdTimeCode displayTime, pxr::UsdTimeCode editTime);

    void Render();

    /// Fired when the user clicks "Edit Material" next to the resolved
    /// binding in the Material Binding section, with the resolved material's
    /// path. Wired by Application to open the Material Editor on that material.
    std::function<void(const std::string&)> OnEditMaterialRequested;

private:
    void ReadTransform();
    void WriteTranslate();
    void WriteRotate();
    void WriteScale();

    /// Snapshot TRS values + keyframe presence when a DragFloat gains focus;
    /// both feed the undo command built on deactivation.
    void CaptureEditStart();

    /// When XformCommonAPI is not applicable (e.g. referenced prim with
    /// xformOp:transform), author standard common-API ops in the current edit
    /// layer so that subsequent XformCommonAPI writes succeed.
    void EnsureCommonAPILayout();

    // Layout helpers – mirroring usdtweak UsdPrimEditor structure
    void RenderPrimHeader(const pxr::UsdPrim& prim);    ///< fixed-height header child
    void RenderVariantSetsSection(const pxr::UsdPrim& prim);
    void RenderTransformSection();
    void RenderPropertiesTable(const pxr::UsdPrim& prim); ///< groups attrs by API schema
    void RenderMaterialBindSection(const pxr::UsdPrim& prim); ///< material:binding info
    /// References/payloads authored on the prim, one row per list-op entry
    /// (explicit/add/prepend/append/delete) with its asset path; clicking a
    /// path browses for a replacement file (undoable).
    void RenderCompositionArcsSection(const pxr::UsdPrim& prim);
    /// Read-only view of the prim's composed assetInfo dictionary
    /// (identifier, name, version, ...).
    void RenderAssetInfoSection(const pxr::UsdPrim& prim);
    void RenderAttrRelSubTable(const std::vector<pxr::UsdAttribute>& attrs,
                               const std::vector<pxr::UsdRelationship>& rels,
                               const pxr::UsdEditTarget& editTarget); ///< inner 3-col table

    PropertyManager*    m_propertyManager = nullptr;
    CommandHistory*     m_commandHistory  = nullptr;
    IconManager*        m_iconManager     = nullptr;
    pxr::UsdStageRefPtr m_stage;
    std::string         m_selectedPrimPath;

    // Cached TRS + pivot values (float matches DragFloat precision)
    pxr::GfVec3f m_translate{ 0.f, 0.f, 0.f };
    pxr::GfVec3f m_rotate   { 0.f, 0.f, 0.f };
    pxr::GfVec3f m_scale    { 1.f, 1.f, 1.f };
    pxr::GfVec3f m_pivot    { 0.f, 0.f, 0.f };
    pxr::UsdGeomXformCommonAPI::RotationOrder
                 m_rotOrder{ pxr::UsdGeomXformCommonAPI::RotationOrderXYZ };

    bool        m_hasXform        = false;
    bool        m_isXformable     = false;
    bool        m_needsRead       = true;
    bool        m_isAnyFieldActive = false; ///< true when a DragFloat is being dragged
    bool        m_xformFallback   = false;  ///< true when values came from matrix decomposition

    // Snapshot of TRS values captured when a DragFloat gains focus,
    // used to build the undo command when the field is deactivated.
    pxr::GfVec3f m_editStartTranslate{ 0.f, 0.f, 0.f };
    pxr::GfVec3f m_editStartRotate   { 0.f, 0.f, 0.f };
    pxr::GfVec3f m_editStartScale    { 1.f, 1.f, 1.f };
    TransformCommand::SamplePresence m_editStartSamples;

    // Timeline time codes (synced by Application)
    pxr::UsdTimeCode m_displayTime = pxr::UsdTimeCode::Default();
    pxr::UsdTimeCode m_editTime    = pxr::UsdTimeCode::Default();

    std::string m_primType;
};

} // namespace UsdLayerManager
