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

#pragma once

#include <ox/claw/claw.hpp>

#include <keel/media.hpp>
#include <turbine/context.hpp>

#include "context.hpp"

namespace studio {

class ItemMaker {
	public:
		ox::String const name;
		ox::String const parentDir;
		ox::String const fileExt;
		constexpr explicit ItemMaker(ox::StringView pName, ox::StringView pParentDir, ox::CRStringView pFileExt) noexcept:
			name(pName),
			parentDir(pParentDir),
			fileExt(pFileExt) {
		}
		virtual ~ItemMaker() noexcept = default;

		/**
		 * Returns path of the file created.
		 * @param ctx
		 * @param pName
		 * @return path of file or error in Result
		 */
		virtual ox::Result<ox::String> write(turbine::Context &ctx, ox::CRStringView pName) const noexcept = 0;
};

template<typename T>
class ItemMakerT: public ItemMaker {
	private:
		T const m_item;
		ox::ClawFormat const m_fmt;
	public:
		constexpr ItemMakerT(
				ox::StringView pDisplayName,
				ox::StringView pParentDir,
				ox::StringView fileExt,
				ox::ClawFormat pFmt = ox::ClawFormat::Metal) noexcept:
			ItemMaker(pDisplayName, pParentDir, fileExt),
			m_fmt(pFmt) {
		}
		constexpr ItemMakerT(
				ox::StringView pDisplayName,
				ox::StringView pParentDir,
				ox::StringView fileExt,
				T pItem,
				ox::ClawFormat pFmt) noexcept:
			ItemMaker(pDisplayName, pParentDir, fileExt),
			m_item(pItem),
			m_fmt(pFmt) {
		}
		constexpr ItemMakerT(
				ox::StringView pDisplayName,
				ox::StringView pParentDir,
				ox::StringView fileExt,
				T &&pItem,
				ox::ClawFormat pFmt) noexcept:
			 ItemMaker(pDisplayName, pParentDir, fileExt),
			 m_item(std::move(pItem)),
			 m_fmt(pFmt) {
		}
		ox::Result<ox::String> write(turbine::Context &ctx, ox::CRStringView pName) const noexcept override {
			auto const path = ox::sfmt("/{}/{}.{}", parentDir, pName, fileExt);
			auto sctx = turbine::applicationData<studio::StudioContext>(ctx);
			keel::createUuidMapping(keelCtx(ctx), path, ox::UUID::generate().unwrap());
			oxReturnError(sctx->project->writeObj(path, m_item, m_fmt));
			return path;
		}
};

}
