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

#pragma once

#include <functional>

#include <ox/std/string.hpp>
#include <ox/std/vector.hpp>

#include <turbine/context.hpp>

#include <studio/itemmaker.hpp>

namespace studio {

class ItemMaker;

struct EditorMaker {
	using Func = std::function<ox::Result<class BaseEditor*>(ox::StringViewCR)>;
	ox::Vector<ox::String> fileTypes;
	Func make;
};

struct Command {
	ox::String name;
	std::function<ox::Error(Project&, ox::SpanView<ox::CString>)> func;
	Command(
		ox::StringParam name,
		std::function<ox::Error(Project&, ox::SpanView<ox::CString>)> func) noexcept:
		name(std::move(name)),
		func(std::move(func)) {}
};

class Module {
	public:
		virtual ~Module() noexcept = default;

		[[nodiscard]]
		virtual ox::String id() const noexcept = 0;

		[[nodiscard]]
		virtual ox::Vector<Command> commands() const;

		[[nodiscard]]
		virtual ox::Vector<EditorMaker> editors(Context &ctx) const;

		[[nodiscard]]
		virtual ox::Vector<ox::UPtr<ItemMaker>> itemMakers(Context&) const;

		[[nodiscard]]
		virtual ox::Vector<ox::UPtr<ItemTemplate>> itemTemplates(Context&) const;

};

template<typename Editor>
[[nodiscard]]
EditorMaker editorMaker(Context &ctx, ox::StringParam ext) noexcept {
	return {
			{std::move(ext)},
			[&ctx](ox::StringViewCR path) -> ox::Result<BaseEditor*> {
				return ox::makeCatch<Editor>(ctx, path);
			}
	};
}

template<typename Editor>
[[nodiscard]]
EditorMaker editorMaker(Context &ctx, std::initializer_list<ox::StringView> exts) noexcept {
	return {
			[&exts] {
				ox::Vector<ox::String> fileTypes;
				fileTypes.reserve(exts.size());
				for (auto &s : exts) {
					fileTypes.emplace_back(s);
				}
				return fileTypes;
			}(),
			[&ctx](ox::StringViewCR path) -> ox::Result<BaseEditor*> {
				return ox::makeCatch<Editor>(ctx, path);
			}
	};
}

}
