/*
 * Copyright 2015 - 2025 gary@drinkingtea.net
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#pragma once

#include <ox/std/span.hpp>
#include <ox/mc/read.hpp>
#ifdef OX_USE_STDLIB
#include <ox/oc/read.hpp>
#endif
#include <ox/std/buffer.hpp>
#include <ox/std/string.hpp>

#include "format.hpp"

namespace ox {

constexpr auto Error_ClawTypeMismatch = 200;
constexpr auto Error_ClawTypeVersionMismatch = 201;

struct ClawHeader {
	String typeName;
	int typeVersion = -1;
	TypeParamPack typeParams;
	ClawFormat fmt = ClawFormat::None;
	const char *data = nullptr;
	std::size_t dataSize = 0;
};

ox::Result<ox::StringView> readClawTypeId(ox::BufferView buff) noexcept;

Result<ClawHeader> readClawHeader(ox::BufferView buff) noexcept;

Result<BufferView> stripClawHeader(ox::BufferView buff) noexcept;

template<typename T>
Error readClaw(ox::BufferView buff, T &val) {
	OX_REQUIRE(header, readClawHeader(buff));
	if (header.typeName != getModelTypeName<T>()) {
		return ox::Error(Error_ClawTypeMismatch, "Claw Read: Type mismatch");
	}
	if (header.typeVersion != getModelTypeVersion<T>()) {
		return ox::Error(Error_ClawTypeVersionMismatch, "Claw Read: Type Version mismatch");
	}
	switch (header.fmt) {
		case ClawFormat::Metal:
		{
			ox::BufferReader br({header.data, header.dataSize});
			MetalClawReader reader(br);
			return model(reader.interface(), &val);
		}
		case ClawFormat::Organic:
		{
#ifdef OX_USE_STDLIB
			OrganicClawReader reader(header.data, header.dataSize);
			return model(&reader, &val);
#else
			break;
#endif
		}
		case ClawFormat::None:
			return ox::Error(1);
	}
	return ox::Error(1);
}

template<typename T>
Result<T> readClaw(ox::BufferView buff) {
	Result<T> val;
	OX_RETURN_ERROR(readClaw(buff, val.value));
	return val;
}

Result<ModelObject> readClaw(TypeStore &ts, BufferView buff) noexcept;

}
