#pragma once

#include "ViewportTile.h"
#include "TransformManipulator.h"
#include "IconManager.h"
#include "../core/CommandHistory.h"

#include <pxr/usd/usd/stage.h>
#include <pxr/usd/sdf/path.h>
#include <imgui.h>

#include <functional>
#include <memory>
#include <vector>
#include <string>

namespace UsdLayerManager {

/// How many tiles the viewport area is divided into.
enum class LayoutMode {
    Single,  ///< 1 tile — full area
    HSplit,  ///< 2 tiles side by side (left | right)
    VSplit,  ///< 2 tiles top / bottom
    Quad,    ///< 4 tiles in a 2×2 grid
};

/// Multi-viewport container.
///
/// Owns N ViewportTile instances, a shared TransformManipulator, and the
/// authoritative selection state.  Manages layout splitting, draggable
/// dividers, and the Maya-style Space-key maximize / restore.
class ViewportPanel {
public:
    ViewportPanel();
    ~ViewportPanel();

    // ── Setup ────────────────────────────────────────────────────────────────
    void SetStage(pxr::UsdStageRefPtr stage);
    void FrameScene();
    void SetCommandHistory(CommandHistory* history);
    void SetIconManager(IconManager* icons);

    /// Push timeline time codes to every tile and the shared manipulator.
    /// displayTime — frame used for all evaluation (render, cameras, bboxes).
    /// editTime    — frame writes are authored at (Default unless Auto-Key).
    void SetTimeCodes(pxr::UsdTimeCode displayTime, pxr::UsdTimeCode editTime);

    // ── Selection (called by SceneHierarchyPanel) ────────────────────────────
    /// Set a single selected prim (clears any multi-selection).
    void SetSelectedPrimPath(const std::string& path);
    /// Set multiple selected prims (from hierarchy Ctrl+click multi-select).
    void SetSelectedPrimPaths(const std::vector<std::string>& paths);

    // ── Main render (called from Application::RenderUI) ──────────────────────
    void Render(bool* p_open = nullptr);

    // ── Callbacks (wired by Application after construction) ──────────────────
    std::function<void(const std::string&)>              OnPrimPicked;
    std::function<void(const std::vector<std::string>&)> OnPrimsPickedRect;

    // ── Forwarding accessors (delegate to focused tile) ──────────────────────
    ViewportCamera&   GetCamera();
    UsdSceneRenderer& GetRenderer();

    // ── Layout ───────────────────────────────────────────────────────────────
    void       SetLayout(LayoutMode mode);
    LayoutMode GetLayout()           const { return m_layout;           }
    int        GetFocusedTileIndex() const { return m_focusedTileIndex; }

    // ── Global preferences ────────────────────────────────────────────────────
    /// Set render delegate on tiles that have no saved delegate yet (empty token).
    /// Called once on startup so the pref default applies to fresh tiles.
    void ApplyDefaultDelegate(const std::string& delegate);
    /// Apply color correction to every tile (always global).
    void ApplyGlobalColorCorrection(int ccMode, const std::string& ocioDisplay,
                                    const std::string& ocioView,
                                    const std::string& ocioColorSpace,
                                    const std::string& ocioLook);

    // ── Settings persistence ─────────────────────────────────────────────────
    /// Load layout and per-tile render settings from a simple INI file.
    void LoadSettings(const std::string& path);
    /// Save current layout and per-tile render settings to a simple INI file.
    void SaveSettings(const std::string& path) const;


private:
    // ── Tile rect helper ─────────────────────────────────────────────────────
    struct TileRect { ImVec2 pos; ImVec2 size; };
    std::vector<TileRect> ComputeTileRects(ImVec2 origin, ImVec2 total) const;

    // ── Render sub-functions ─────────────────────────────────────────────────
    /// Draws the global vertical left toolbar (layout buttons + tool mode buttons).
    /// Occupies a reserved strip of width kToolbarW on the left of the content area.
    void RenderGlobalLeftToolbar(ImVec2 contentPos, ImVec2 contentSize);
    void DrawDividers(ImVec2 origin, ImVec2 total);
    void HandleMaximizeInput(int hoveredTileIndex);
    /// Returns true when the mouse is currently over a divider hit-zone or a
    /// divider drag is already in progress.  Used to suppress tile rect-selection
    /// when the user is resizing tiles.
    bool IsMouseOverDivider(ImVec2 origin, ImVec2 total) const;

    /// Width (px) of the reserved left toolbar strip.
    static constexpr float kToolbarW = 40.0f;

    // ── Selection management ─────────────────────────────────────────────────
    /// Push the current shared selection into every tile and the manipulator.
    void BroadcastSelection();
    /// Update the focused tile index and update the gizmo's selected prim.
    void UpdateFocusTile(int idx);

    // ── Tile setup ───────────────────────────────────────────────────────────
    /// (Re)create tiles so that exactly `count` tiles exist, reusing existing
    /// ones where possible to preserve camera/settings state.
    void EnsureTileCount(int count);
    /// Wire pick callbacks for tile at index `i`.
    void WireCallbacks(int i);

    // ── Tiles ────────────────────────────────────────────────────────────────
    std::vector<std::unique_ptr<ViewportTile>> m_tiles;

    // ── Shared manipulator ───────────────────────────────────────────────────
    TransformManipulator m_manipulator;

    // ── Shared selection (authoritative) ────────────────────────────────────
    pxr::SdfPathVector m_selectedSdfPaths;
    std::string        m_selectedPrimPath;

    // ── Layout state ─────────────────────────────────────────────────────────
    LayoutMode m_layout  = LayoutMode::Single;
    float      m_splitH  = 0.5f; ///< Horizontal divider (0–1); used by HSplit + Quad
    float      m_splitV  = 0.5f; ///< Vertical   divider (0–1); used by VSplit + Quad

    // Divider drag state
    bool  m_draggingDivH = false; ///< Dragging the vertical   line (changes m_splitH)
    bool  m_draggingDivV = false; ///< Dragging the horizontal line (changes m_splitV)

    // ── Maximize state ───────────────────────────────────────────────────────
    int        m_maximizedTileIndex   = -1;             ///< -1 = not maximised
    LayoutMode m_layoutBeforeMaximize = LayoutMode::Single;
    float      m_splitHBefore         = 0.5f;
    float      m_splitVBefore         = 0.5f;

    // ── Focus ────────────────────────────────────────────────────────────────
    int m_focusedTileIndex = 0;

    // ── Shared dependencies forwarded to tiles ───────────────────────────────
    pxr::UsdStageRefPtr m_stage;
    IconManager*        m_iconManager    = nullptr;
    CommandHistory*     m_commandHistory = nullptr;
    pxr::UsdTimeCode    m_displayTime    = pxr::UsdTimeCode::Default();
    pxr::UsdTimeCode    m_editTime       = pxr::UsdTimeCode::Default();
};

} // namespace UsdLayerManager
