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

#include <algorithm>

#include <imgui.h>

#include <studio/imguiutil.hpp>

#include "newmenu.hpp"

namespace studio {

NewMenu::NewMenu(keel::Context &kctx) noexcept: m_kctx{kctx} {
	setTitle("New Item");
}

void NewMenu::open() noexcept {
	m_stage = Stage::Opening;
	m_selectedType = 0;
	m_itemName = "";
	m_typeName = "";
	m_useDefaultPath = true;
	m_explorer.setModel(buildFileTreeModel(
		m_explorer,
		[](ox::StringViewCR, ox::FileStat const &s) {
			return s.fileType == ox::FileType::Directory;
		}).or_value(ox::UPtr<FileTreeModel>{}));
}

void NewMenu::openPath(ox::StringViewCR path) noexcept {
	open();
	m_useDefaultPath = false;
	std::ignore = m_explorer.setSelectedPath(path);
}

void NewMenu::close() noexcept {
	m_stage = Stage::Closed;
	m_open = false;
}

bool NewMenu::isOpen() const noexcept {
	return m_open;
}

void NewMenu::draw(Context &sctx) noexcept {
	if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
		close();
		return;
	}
	switch (m_stage) {
		case Stage::Opening:
			ImGui::OpenPopup(title().c_str());
			m_stage = Stage::NewItemType;
			m_open = true;
			[[fallthrough]];
		case Stage::NewItemType:
			drawNewItemType(sctx);
			break;
		case Stage::NewItemTransitioningToPath:
		case Stage::NewItemPath:
			drawNewItemPath(sctx);
			break;
		case Stage::NewItemTemplate:
			drawNewItemTemplate(sctx);
			break;
		case Stage::Closed:
			m_open = false;
			break;
	}
}

void NewMenu::addItemMaker(ox::UPtr<ItemMaker> &&im) noexcept {
	m_types.emplace_back(std::move(im));
	std::sort(
			m_types.begin(), m_types.end(),
			[](ox::UPtr<ItemMaker> const &im1, ox::UPtr<ItemMaker> const &im2) {
				 return im1->typeDisplayName() < im2->typeDisplayName();
			});
}

void NewMenu::installItemTemplate(ox::UPtr<ItemTemplate> &&tmplt) noexcept {
	for (auto const &im : m_types) {
		if (im->installTemplate(std::move(tmplt))) {
			break;
		}
	}
}

void NewMenu::drawNewItemType(Context const &sctx) noexcept {
	setSize({280, 180});
	drawWindow(sctx.tctx, m_open, [this] {
		ig::ListBox("Item Type", [&](size_t const i) -> ox::CStringView {
			return m_types[i]->typeDisplayName();
		}, m_types.size(), m_selectedType, {200, 100});
		auto const &im = *m_types[m_selectedType];
		drawFirstPageButtons(im.itemTemplates().size() == 1 ?
			Stage::NewItemTransitioningToPath : Stage::NewItemTemplate);
		if (m_stage == Stage::NewItemTransitioningToPath || m_stage == Stage::NewItemTemplate) {
			if (m_useDefaultPath) {
				std::ignore = m_explorer.setSelectedPath(im.defaultPath());
			}
		}
	});
}

void NewMenu::drawNewItemTemplate(Context const &sctx) noexcept {
	setSize({280, 180});
	drawWindow(sctx.tctx, m_open, [this] {
		auto const &templates =
			m_types[m_selectedType]->itemTemplates();
		ig::ListBox("Template", [&](size_t const i) -> ox::CStringView {
			return templates[i]->name();
		}, templates.size(), m_selectedTemplate, {200, 100});
		drawButtons(Stage::NewItemTransitioningToPath);
	});
}

void NewMenu::drawNewItemPath(Context &sctx) noexcept {
	setSize({380, 340});
	drawWindow(sctx.tctx, m_open, [this, &sctx] {
		if (m_stage == Stage::NewItemTransitioningToPath) [[unlikely]] {
			ImGui::SetKeyboardFocusHere();
			m_stage = Stage::NewItemPath;
		}
		ig::InputText("Name", m_itemName);
		ImGui::NewLine();
		ImGui::Text("Path");
		auto const vp = ImGui::GetContentRegionAvail();
		m_explorer.draw(sctx, {vp.x, vp.y - 50});
		drawLastPageButtons(sctx);
	});
}

void NewMenu::drawButtons(Stage const next) noexcept {
	auto const scale = ig::dpiScale();
	ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 198 * scale);
	ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 22 * scale);
	ImVec2 const btnSz{60 * scale, ig::BtnSz.y * scale};
	if (ImGui::Button("Back", btnSz)) {
		if (auto const p = m_prev.back(); p.ok()) {
			m_stage = *p.value;
		}
		m_prev.pop_back();
	}
	ImGui::SameLine();
	if (ImGui::Button("Next", btnSz)) {
		m_prev.emplace_back(m_stage);
		m_stage = next;
	}
	ImGui::SameLine();
	if (ImGui::Button("Cancel", btnSz)) {
		ImGui::CloseCurrentPopup();
		m_stage = Stage::Closed;
	}
}

void NewMenu::drawFirstPageButtons(Stage const next) noexcept {
	auto const scale = ig::dpiScale();
	ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 130 * scale);
	ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 22 * scale);
	ImVec2 const btnSz{60 * scale, ig::BtnSz.y * scale};
	if (ImGui::Button("Next", btnSz)) {
		m_prev.emplace_back(m_stage);
		m_stage = next;
	}
	ImGui::SameLine();
	if (ImGui::Button("Cancel", btnSz)) {
		ImGui::CloseCurrentPopup();
		m_stage = Stage::Closed;
	}
}

void NewMenu::drawLastPageButtons(Context &sctx) noexcept {
	auto const scale = ig::dpiScale();
	ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 198 * scale);
	ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 22 * scale);
	ImVec2 const btnSz{60 * scale, ig::BtnSz.y * scale};
	if (ImGui::Button("Back", btnSz)) {
		if (auto const p = m_prev.back(); p.ok()) {
			m_stage = *p.value;
		}
		m_prev.pop_back();
	}
	ImGui::SameLine();
	if (ImGui::Button("Finish", btnSz)) {
		finish(sctx);
	}
	ImGui::SameLine();
	if (ImGui::Button("Quit", btnSz)) {
		ImGui::CloseCurrentPopup();
		m_stage = Stage::Closed;
	}
}

void NewMenu::finish(Context &sctx) noexcept {
	if (m_itemName.size() == 0) {
		oxLogError(ox::Error{1, "New file error: no file name"});
		return;
	}
	auto const &im = *m_types[m_selectedType];
	auto const path = sfmt("{}/{}.{}",
		m_explorer.selectedPath().or_value(ox::String{}), m_itemName, im.fileExt());
	if (sctx.project->exists(path)) {
		oxLogError(ox::Error{1, "New file error: file already exists"});
		return;
	}
	if (auto const err = im.write(sctx, path, m_selectedTemplate)) {
		oxLogError(err);
		return;
	}
	finished.emit(path);
	m_stage = Stage::Closed;
}

}
