/*
 * Copyright 2023 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
 */

#include <nostalgia/gfx/gfx.hpp>

#include "worldeditorview.hpp"

namespace jasper::world {

WorldEditorView::WorldEditorView(studio::Context &sctx, WorldStatic const &worldStatic):
		m_sctx{sctx},
		m_nctx{ngfx::init(m_sctx.tctx, {.glInstallDrawer = false}).unwrapThrow()},
		m_worldStatic{worldStatic},
		m_world{*m_nctx, m_worldStatic} {}

ox::Error WorldEditorView::setupTile(
		uint32_t const lyr,
		uint32_t const x,
		uint32_t const y) noexcept {
	m_world.setupTile(lyr, x, y);
	return {};
}

void WorldEditorView::setupTiles() noexcept {
	m_world.setupTiles();
}

ox::Error WorldEditorView::setupWorld() noexcept {
	glutils::resizeInitFrameBuffer(m_frameBuffer, ngfx::gl::drawSize(m_scale));
	if (m_columns != m_worldStatic.columns || m_rows != m_worldStatic.rows) {
		OX_RETURN_ERROR(m_highlighter.setup({m_worldStatic.columns, m_worldStatic.rows}));
		m_columns = m_worldStatic.columns;
		m_rows = m_worldStatic.rows;
		m_selection.reset();
	}
	return m_world.setupDisplay();
}

void WorldEditorView::draw(ox::Size const &targetSz) noexcept {
	auto const scaleSz = targetSz / ngfx::gl::drawSize(1);
	if (m_scaleSz != scaleSz) [[unlikely]] {
		m_scale = ox::max(1, ox::max(scaleSz.width, scaleSz.height));
		m_scaleSz = ngfx::gl::drawSize(m_scale);
		glutils::resizeInitFrameBuffer(m_frameBuffer, ngfx::gl::drawSize(m_scale));
	}
	glutils::FrameBufferBind const frameBufferBind(m_frameBuffer);
	if (m_animateWorld) {
		auto const wakeUp = m_world.update();
		if (wakeUp.ok()) {
			turbine::requireRefreshWithin(m_sctx.tctx, wakeUp.value);
		}
	}
	ngfx::gl::draw(*m_nctx, m_scale);
	m_highlighter.draw();
}

void WorldEditorView::clearSelection() noexcept {
	if (m_selection) {
		studio::iterateSelection(*m_selection, [this](int32_t x, int32_t y) {
			std::ignore = m_highlighter.setTileHighlight({x, y}, false);
		});
	}
}

void WorldEditorView::setSelection(studio::Selection const &sel) noexcept {
	clearSelection();
	m_selection.emplace(sel);
	studio::iterateSelection(*m_selection, [this](int32_t x, int32_t y) {
		std::ignore = m_highlighter.setTileHighlight({x, y}, true);
	});
}

glutils::FrameBuffer const &WorldEditorView::framebuffer() const noexcept {
	return m_frameBuffer;
}

ox::Size WorldEditorView::drawSize() const noexcept {
	return ngfx::gl::drawSize(m_scale);
}

}
