#include "windows_window_state.h"
#include <iostream>

#include "pixel_format_convert.h"
#include "misc/scope_exit.h"

bool windows_window_state::init(ID3D11Device* in_device, IDXGIFactory* in_factory, mirage_window* in_window) {
	dx_device    = in_device;
	dxgi_factory = in_factory;

	const auto size          = in_window->get_window_frame_size();
	const auto window_handle = in_window->get_window_handle();

#ifdef MIRAGE_USE_HDR
	constexpr auto sg_format = MIRAGE_HDR_FORMAT;
#else
	constexpr auto sg_format = MIRAGE_PIXEL_FORMAT;
#endif
	const auto format = sg_pixel_format_to_dxgi_srv(sg_format);

	// 创建D3D11渲染目标视图
	DXGI_SWAP_CHAIN_DESC swap_chain_desc = {
		.BufferDesc = {
			.Width = static_cast<UINT>(size.x()),
			.Height = static_cast<UINT>(size.y()),
			.RefreshRate = {
				.Numerator = 240,
				.Denominator = 1
			},
			.Format = format,
		},
		.SampleDesc = {
			.Count = 1,
			.Quality = 0
		},
		.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT,
		.BufferCount = 1,
		.OutputWindow = (HWND) window_handle,
		.Windowed = TRUE
	};

	// 创建交换链
	HRESULT hr = dxgi_factory->CreateSwapChain(dx_device, &swap_chain_desc, &dx_swap_chain);
	if (FAILED(hr)) {
		std::cerr << "mirage: " << "Failed to create DXGI Swap Chain. HRESULT: 0x" << std::hex << hr << std::dec <<
				std::endl;
		return false;
	}

	// 获取后台缓冲区
	ID3D11Texture2D* back_buffer = nullptr;
	hr                           = dx_swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**) &back_buffer);
	if (FAILED(hr)) {
		std::cerr << "mirage: " << "Failed to get back buffer from DXGI Swap Chain. HRESULT: 0x" << std::hex << hr <<
				std::dec << std::endl;
		return false;
	}
	ON_SCOPE_EXIT { back_buffer->Release(); };

	// 创建渲染目标视图
	ID3D11RenderTargetView* render_target_view = nullptr;
	hr = dx_device->CreateRenderTargetView(back_buffer, nullptr, &render_target_view);
	if (FAILED(hr)) {
		std::cerr << "mirage: " << "Failed to create render target view. HRESULT: 0x" << std::hex << hr << std::dec <<
				std::endl;
		return false;
	}

// #ifdef MIRAGE_USE_HDR
// 	// 设置HDR元数据
// 	DXGI_HDR_METADATA_HDR10 metadata = {};
// 	metadata.MaxMasteringLuminance = 1000 * 10000; // 1000尼特
// 	metadata.MinMasteringLuminance = 0.001 * 10000; // 0.001尼特
// 	// ...设置其他元数据
// 	dx_swap_chain->SetHDRMetaData(DXGI_HDR_METADATA_TYPE_HDR10, sizeof(metadata), &metadata);
// #endif

	swapchain.d3d11.render_view        = render_target_view;
	swapchain.width                    = static_cast<int>(size.x());
	swapchain.height                   = static_cast<int>(size.y());
	swapchain.color_format             = sg_format;
	swapchain.depth_format             = SG_PIXELFORMAT_NONE;
	swapchain.sample_count             = 1;
	swapchain.d3d11.resolve_view       = nullptr;
	swapchain.d3d11.depth_stencil_view = nullptr;
	return true;
}

void windows_window_state::clear() {
	dx_swap_chain->Release();
	get_dx_render_target_view()->Release();
}

void windows_window_state::present() { dx_swap_chain->Present(vsync ? 1 : 0, 0); }

void windows_window_state::resize(const Eigen::Vector2i& size) {
	if (size.x() == 0 || size.y() == 0) { return; }

	// 保存当前格式
	D3D11_RENDER_TARGET_VIEW_DESC rtv_desc              = {};
	auto                          dx_render_target_view = get_dx_render_target_view();
	if (dx_render_target_view) {
		dx_render_target_view->GetDesc(&rtv_desc);

		// 释放旧的渲染目标视图
		dx_render_target_view->Release();
	}

	// 重设交换链缓冲区大小
	HRESULT hr = dx_swap_chain->ResizeBuffers(
	                                          1,
	                                          // 缓冲区数量
	                                          size.x(),
	                                          // 新宽度
	                                          size.y(),
	                                          // 新高度
	                                          rtv_desc.Format,
	                                          // 保持原格式
	                                          0 // 标志
	                                         );

	if (FAILED(hr)) {
		// 重设失败
		std::cerr << "重设交换链缓冲区失败" << std::endl;
		return;
	}

	// 获取新的后台缓冲区
	ID3D11Texture2D* back_buffer = nullptr;
	hr                           = dx_swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**) &back_buffer);
	if (FAILED(hr)) {
		std::cerr << "获取后台缓冲区失败" << std::endl;
		return;
	}
	ON_SCOPE_EXIT { back_buffer->Release(); };

	// 创建新的渲染目标视图
	hr = dx_device->CreateRenderTargetView(back_buffer,
	                                       nullptr,
	                                       (ID3D11RenderTargetView**) &swapchain.d3d11.render_view);
	if (FAILED(hr)) {
		std::cerr << "创建新的渲染目标视图失败" << std::endl;
		return;
	}
}
