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

#include <imgui.h>

#include <ox/std/memory.hpp>

#include <keel/media.hpp>

#include <nostalgia/core/gfx.hpp>

#include "paletteeditor.hpp"
#include "paletteeditor-imgui.hpp"

namespace nostalgia::core {

PaletteEditorImGui::PaletteEditorImGui(studio::StudioContext &sctx, ox::CRStringView path):
	Editor(path),
	m_sctx(sctx),
	m_tctx(sctx.tctx),
	m_pal(*keel::readObj<Palette>(keelCtx(m_tctx), ox::FileAddress(itemPath())).unwrapThrow()) {
	undoStack()->changeTriggered.connect(this, &PaletteEditorImGui::handleCommand);
}

void PaletteEditorImGui::keyStateChanged(turbine::Key key, bool down) {
	if (!down) {
		return;
	}
	if (key >= turbine::Key::Num_1 && key <= turbine::Key::Num_9) {
		if (turbine::buttonDown(m_tctx, turbine::Key::Mod_Alt)) {
			m_page = ox::min<std::size_t>(
					  static_cast<uint32_t>(key - turbine::Key::Num_1), m_pal.pages.size() - 1);
		}
	} else if (key == turbine::Key::Num_0) {
		if (turbine::buttonDown(m_tctx, turbine::Key::Mod_Alt)) {
			m_selectedColorRow =
					ox::min<std::size_t>(
					  static_cast<uint32_t>(key - turbine::Key::Num_1 + 9), m_pal.pages.size() - 1);
		}
	}

}

void PaletteEditorImGui::draw(studio::StudioContext&) noexcept {
	auto const paneSize = ImGui::GetContentRegionAvail();
	{
		ImGui::BeginChild("Pages", ImVec2(250, paneSize.y), true);
		drawPagesEditor();
		ImGui::EndChild();
	}
	ImGui::SameLine();
	{
		ImGui::BeginChild("Colors", ImVec2(-1, paneSize.y), true);
		drawColorsEditor();
		ImGui::EndChild();
	}
}

ox::Error PaletteEditorImGui::saveItem() noexcept {
	return m_sctx.project->writeObj(itemPath(), m_pal);
}

void PaletteEditorImGui::drawColumn(ox::CStringView txt) noexcept {
	ImGui::TableNextColumn();
	ImGui::SetCursorPosX(
			ImGui::GetCursorPosX() + ImGui::GetColumnWidth() - ImGui::CalcTextSize(txt.data()).x);
	ImGui::Text("%s", txt.c_str());
}

void PaletteEditorImGui::drawColumn(uint64_t i) noexcept {
	ox::Array<char, 10> numStr;
	ox::itoa(i, numStr.data());
	drawColumn(numStr.data());
}

void PaletteEditorImGui::drawColorsEditor() noexcept {
	constexpr auto tableFlags = ImGuiTableFlags_RowBg;
	auto const colorsSz = ImGui::GetContentRegionAvail();
	auto const colorEditor = m_selectedColorRow < colors(m_pal, m_page);
	auto const colorEditorWidth = 220;
	static constexpr auto toolbarHeight = 40;
	{
		auto const sz = ImVec2(70, 24);
		if (ImGui::Button("Add", sz)) {
			auto const colorSz = static_cast<int>(colors(m_pal, m_page));
			constexpr Color16 c = 0;
			undoStack()->push(ox::make_unique<AddColorCommand>(&m_pal, c, m_page, colorSz));
		}
		ImGui::SameLine();
		ImGui::BeginDisabled(m_selectedColorRow >= colors(m_pal, m_page));
		{
			if (ImGui::Button("Remove", sz)) {
				undoStack()->push(
						ox::make_unique<RemoveColorCommand>(
								&m_pal,
								color(m_pal, m_page, static_cast<std::size_t>(m_selectedColorRow)),
								m_page,
								static_cast<int>(m_selectedColorRow)));
				m_selectedColorRow = ox::min(colors(m_pal, m_page) - 1, m_selectedColorRow);
			}
			ImGui::SameLine();
			ImGui::BeginDisabled(m_selectedColorRow <= 0);
			{
				if (ImGui::Button("Move Up", sz)) {
					undoStack()->push(ox::make_unique<MoveColorCommand>(&m_pal, m_page, m_selectedColorRow, -1));
					--m_selectedColorRow;
				}
			}
			ImGui::EndDisabled();
			ImGui::SameLine();
			ImGui::BeginDisabled(m_selectedColorRow >= colors(m_pal, m_page) - 1);
			{
				if (ImGui::Button("Move Down", sz)) {
					undoStack()->push(ox::make_unique<MoveColorCommand>(&m_pal, m_page, m_selectedColorRow, 1));
					++m_selectedColorRow;
				}
			}
			ImGui::EndDisabled();
		}
		ImGui::EndDisabled();
	}
	auto const tblWidth = (colorsSz.x - colorEditorWidth - 8) * colorEditor;
	ImGui::BeginTable("Colors", 5, tableFlags, ImVec2(tblWidth, colorsSz.y - (toolbarHeight + 5)));
	{
		ImGui::TableSetupColumn("Idx", ImGuiTableColumnFlags_WidthFixed, 25);
		ImGui::TableSetupColumn("Red", ImGuiTableColumnFlags_WidthFixed, 50);
		ImGui::TableSetupColumn("Green", ImGuiTableColumnFlags_WidthFixed, 50);
		ImGui::TableSetupColumn("Blue", ImGuiTableColumnFlags_WidthFixed, 50);
		ImGui::TableSetupColumn("Color Preview", ImGuiTableColumnFlags_NoHide);
		ImGui::TableHeadersRow();
		for (auto i = 0u; auto const c : m_pal.pages[m_page]) {
			ImGui::PushID(static_cast<int>(i));
			ImGui::TableNextRow();
			drawColumn(i);
			drawColumn(red16(c));
			drawColumn(green16(c));
			drawColumn(blue16(c));
			ImGui::TableNextColumn();
			auto const ic = ImGui::GetColorU32(ImVec4(redf(c), greenf(c), bluef(c), 1));
			ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ic);
			if (ImGui::Selectable("##ColorRow", i == m_selectedColorRow, ImGuiSelectableFlags_SpanAllColumns)) {
				m_selectedColorRow = i;
			}
			ImGui::PopID();
			++i;
		}
	}
	ImGui::EndTable();
	if (colorEditor) {
		ImGui::SameLine();
		ImGui::BeginChild("ColorEditor", ImVec2(colorEditorWidth, -1), true);
		drawColorEditor();
		ImGui::EndChild();
	}
}

void PaletteEditorImGui::drawPagesEditor() noexcept {
	constexpr auto tableFlags = ImGuiTableFlags_RowBg;
	auto const paneSz = ImGui::GetContentRegionAvail();
	constexpr auto toolbarHeight = 40;
	auto const btnSz = ImVec2(paneSz.x / 3 - 5.5f, 24);
	if (ImGui::Button("Add", btnSz)) {
		undoStack()->push(ox::make_unique<AddPageCommand>(m_pal));
		m_page = m_pal.pages.size() - 1;
	}
	ImGui::SameLine();
	if (ImGui::Button("Remove", btnSz)) {
		undoStack()->push(ox::make_unique<RemovePageCommand>(m_pal, m_page));
		m_page = std::min(m_page, m_pal.pages.size() - 1);
	}
	ImGui::SameLine();
	if (ImGui::Button("Duplicate", btnSz)) {
		undoStack()->push(ox::make_unique<DuplicatePageCommand>(m_pal, m_page, m_pal.pages.size()));
	}
	ImGui::BeginTable("PageSelect", 2, tableFlags, ImVec2(paneSz.x, paneSz.y - (toolbarHeight + 5)));
	{
		ImGui::TableSetupColumn("Page", ImGuiTableColumnFlags_WidthFixed, 60);
		ImGui::TableSetupColumn("Colors", ImGuiTableColumnFlags_NoHide);
		ImGui::TableHeadersRow();
		for (auto i = 0u; i < m_pal.pages.size(); ++i) {
			ImGui::PushID(static_cast<int>(i));
			ImGui::TableNextRow();
			drawColumn(i + 1);
			drawColumn(colors(m_pal, i));
			ImGui::SameLine();
			if (ImGui::Selectable("##PageRow", i == m_page, ImGuiSelectableFlags_SpanAllColumns)) {
				m_page = i;
			}
			ImGui::PopID();
		}
	}
	ImGui::EndTable();
}

void PaletteEditorImGui::drawColorEditor() noexcept {
	auto const c = color(m_pal, m_page, m_selectedColorRow);
	int r = red16(c);
	int g = green16(c);
	int b = blue16(c);
	int const a = alpha16(c);
	ImGui::InputInt("Red", &r, 1, 5);
	ImGui::InputInt("Green", &g, 1, 5);
	ImGui::InputInt("Blue", &b, 1, 5);
	auto const newColor = color16(r, g, b, a);
	if (c != newColor) {
		undoStack()->push(ox::make_unique<UpdateColorCommand>(
				&m_pal, m_page, static_cast<int>(m_selectedColorRow), c, newColor));
	}
}

ox::Error PaletteEditorImGui::handleCommand(studio::UndoCommand const*cmd) noexcept {
	if (dynamic_cast<AddPageCommand const*>(cmd)) {
		m_page = m_pal.pages.size() - 1;
	} else if (dynamic_cast<RemovePageCommand const*>(cmd)) {
		m_page = ox::min(m_page, m_pal.pages.size() - 1);
	} else if (auto const dupPageCmd = dynamic_cast<DuplicatePageCommand const*>(cmd)) {
		m_page = ox::clamp<size_t>(dupPageCmd->insertIdx(), 0, m_pal.pages.size() - 1);
	}
	return {};
}

}
