#pragma once    
#include "D3D12CommonHeader.h"
#include "D3D12Resources.h"

namespace XEngine::graphics::d3d12 {

/**
 * @class d3d12_surface
 * @brief 管理 D3D12 交换链和渲染目标的表面类
 *
 * @details
 * 该类封装了 Direct3D 12 的交换链（Swap Chain）和后台缓冲区管理，
 * 提供渲染表面的完整生命周期管理。
 *
 * ## 核心职责
 *
 * - **交换链管理**：创建和管理 IDXGISwapChain4，处理前后缓冲区交换
 * - **渲染目标管理**：为每个后台缓冲区创建和维护渲染目标视图（RTV）
 * - **视口和裁剪矩形**：管理渲染区域的视口和裁剪设置
 * - **窗口关联**：与平台窗口绑定，处理窗口大小调整
 *
 * ## 多缓冲机制
 *
 * 使用 `frame_buffer_count`（通常为 3）个后台缓冲区实现三重缓冲：
 * - 减少画面撕裂
 * - 提高 CPU-GPU 并行性
 * - 平滑帧率波动
 *
 * ## 生命周期
 *
 * @code
 * d3d12_surface surface(window);
 * surface.create_swap_chain(factory, cmd_queue, DXGI_FORMAT_R8G8B8A8_UNORM);
 * 
 * // 渲染循环
 * surface.present();  // 呈现当前帧
 * surface.resize();   // 窗口大小改变时调用
 * 
 * // 自动析构时释放资源
 * @endcode
 *
 * @see IDXGISwapChain4
 * @see ID3D12Resource
 * @see descriptor_handle
 */
class d3d12_surface
{
public:
    /**
     * @brief 构造函数，绑定到指定窗口
     * 
     * @param window 平台窗口对象
     * 
     * @details
     * 仅保存窗口引用，不创建交换链。
     * 必须随后调用 create_swap_chain() 完成初始化。
     * 
     * @pre window.handle() 必须返回有效的窗口句柄
     */
    explicit d3d12_surface(platform::window window)
        :_window(window)
    {
        assert(window.handle());
    }

    /**
     * @brief 析构函数，自动释放所有资源
     * 
     * @details
     * 调用 release() 清理交换链和渲染目标资源。
     */
    ~d3d12_surface(){ release(); }

#if USE_STL_VECTOR
    DISABLE_COPY(d3d12_surface)

    /**
     * @brief 移动构造函数
     * 
     * @param o 要移动的源对象
     * 
     * @details
     * 转移所有资源所有权，将源对象置为空状态。
     * 用于 vector 扩容时安全转移资源。
     */
    constexpr d3d12_surface(d3d12_surface&& o) noexcept
        : _swap_chain{o._swap_chain}, _window{o._window}, _current_bb_index{o._current_bb_index}
        , _viewport{o._viewport}, _scissor_rect{o._scissor_rect}
        , _allow_tearing{o._allow_tearing}, _present_flags{o._present_flags}
    {
        for (u32 i = 0; i < frame_buffer_count; ++i)
        {
            _render_target_data[i].resource = o._render_target_data[i].resource;
            _render_target_data[i].rtv = o._render_target_data[i].rtv;
        }
        
        o.reset();
    }

    /**
     * @brief 移动赋值运算符
     * 
     * @param o 要移动的源对象
     * @return 当前对象引用
     * 
     * @details
     * 先释放当前资源，再转移所有权。
     */
    constexpr d3d12_surface& operator=(d3d12_surface&& o) noexcept
    {
        assert(this != &o);
        if (this != &o)
        {
            release();
            move(o);
        }
        return *this;
    }

#else
    DISABLE_COPY_AND_MOVE(d3d12_surface);
#endif


    /**
     * @brief 创建交换链和渲染目标视图
     * 
     * @param factory DXGI 工厂对象，用于创建交换链
     * @param cmd_queue 命令队列，交换链将与此队列同步
     * @param format 后台缓冲区的像素格式（如 DXGI_FORMAT_R8G8B8A8_UNORM）
     * 
     * @details
     * 执行以下操作：
     * 1. 创建 IDXGISwapChain4 对象
     * 2. 获取所有后台缓冲区资源
     * 3. 为每个后台缓冲区创建 RTV
     * 4. 初始化视口和裁剪矩形
     * 
     * @pre factory 和 cmd_queue 必须有效
     * @pre 尚未创建交换链（或已调用 release()）
     */
    void create_swap_chain(IDXGIFactory7* factory, ID3D12CommandQueue* cmd_queue, DXGI_FORMAT format);

    /**
     * @brief 呈现当前渲染帧
     * 
     * @details
     * 调用 IDXGISwapChain::Present() 将当前后台缓冲区内容显示到屏幕。
     * 呈现后，后台缓冲区索引自动递增（轮转）。
     * 
     * @note 使用 DXGI_SWAP_EFFECT_FLIP_DISCARD 模式时，
     *       呈现后当前后台缓冲区内容不再有效
     */
    void present() const;

    /**
     * @brief 调整交换链大小以匹配窗口
     * 
     * @details
     * 当窗口大小改变时调用此方法：
     * 1. 释放旧的渲染目标资源
     * 2. 调整交换链缓冲区大小
     * 3. 重新创建渲染目标视图
     * 4. 更新视口和裁剪矩形
     * 
     * @note 必须在 GPU 完成使用当前资源后调用
     */
    void resize();

    /**
     * @brief 获取渲染表面宽度
     * @return 宽度（像素）
     */
    u32 width();

    /**
     * @brief 获取渲染表面高度
     * @return 高度（像素）
     */
    u32 height();

    /**
     * @brief 获取当前后台缓冲区资源
     * @return 指向 ID3D12Resource 的指针
     * 
     * @details
     * 返回当前帧应渲染到的后台缓冲区。
     * 索引由 _current_bb_index 指定，每次 present() 后更新。
     */
    constexpr ID3D12Resource *const back_buffer() const {return _render_target_data[_current_bb_index].resource;}

    /**
     * @brief 获取当前后台缓冲区的渲染目标视图句柄
     * @return RTV 描述符句柄
     * 
     * @details
     * 用于 OMSetRenderTargets() 绑定渲染目标。
     */
    constexpr descriptor_handle rtv() const {return _render_target_data[_current_bb_index].rtv;}

    /**
     * @brief 获取视口描述
     * @return D3D12_VIEWPORT 常量引用
     * 
     * @details
     * 用于 RSSetViewports() 设置光栅化视口。
     */
    constexpr const D3D12_VIEWPORT& viewport() const {return _viewport;}

    /**
     * @brief 获取裁剪矩形描述
     * @return D3D12_RECT 常量引用
     * 
     * @details
     * 用于 RSSetScissorRects() 设置裁剪区域。
     * 裁剪区域外的像素将被丢弃。
     */
    constexpr const D3D12_RECT& scissor_rect() const {return _scissor_rect;}

private:

#if USE_STL_VECTOR
    constexpr void move(d3d12_surface& o)
    {
        _swap_chain = o._swap_chain;
        for (u32 i = 0; i < frame_buffer_count; ++i)
        {
            _render_target_data[i] = o._render_target_data[i];
        }
        _window = o._window;
        _current_bb_index = o._current_bb_index;
        _viewport = o._viewport;
        _scissor_rect = o._scissor_rect;
        _allow_tearing = o._allow_tearing;
        _present_flags = o._present_flags;
        
        o.reset();
    }


    constexpr void reset()
    {
        _swap_chain = nullptr;
        for (u32 i = 0; i < frame_buffer_count; ++i)
        {
            _render_target_data[i] = {};
        }
        _window = {};
        _current_bb_index = 0;
        _viewport = {};
        _scissor_rect = {};
        _allow_tearing = 0;
        _present_flags = 0;
    }

#endif

    /**
     * @brief 释放所有资源
     * 
     * @details
     * 释放交换链和所有后台缓冲区资源。
     * 使用延迟释放机制确保 GPU 安全。
     */
    void release();

    /**
     * @brief 完成资源创建的最终设置
     * 
     * @details
     * 在创建或调整大小后调用，设置视口和裁剪矩形。
     */
    void finalize();

    /**
     * @struct render_target_data
     * @brief 单个后台缓冲区的渲染目标数据
     *
     * @details
     * 每个后台缓冲区对应一个此结构体，存储：
     * - 资源指针：实际的缓冲区纹理资源
     * - RTV 句柄：用于绑定到渲染管线
     */
    struct render_target_data
    {
        ID3D12Resource* resource{nullptr};  ///< 后台缓冲区资源
        descriptor_handle rtv{};            ///< 渲染目标视图描述符句柄
    };

    IDXGISwapChain4*        _swap_chain{nullptr};                   ///< DXGI 交换链对象
    render_target_data      _render_target_data[frame_buffer_count];///< 后台缓冲区数据数组
    platform::window        _window{};                              ///< 关联的平台窗口
    mutable u32             _current_bb_index{0};                   ///< 当前后台缓冲区索引
    D3D12_VIEWPORT          _viewport{};                            ///< 视口描述
    D3D12_RECT              _scissor_rect{};                        ///< 裁剪矩形
    u32                     _allow_tearing{ 0 };                    ///< 是否允许撕裂
    u32                     _present_flags{ 0 };                    ///< 呈现标志位
};
    
}
