/*
 * 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/assert.hpp>
#include <ox/std/bit.hpp>
#include <ox/std/error.hpp>

#include "optype.hpp"

namespace ox {

namespace detail {

template<typename T>
class FieldCounter {
	public:
		std::size_t fields = 0;

		template<typename U = std::nullptr_t>
		constexpr ox::Error setTypeInfo(StringViewCR = "", int = 0, const Vector<String>& = {}, std::size_t = 0) {
			return {};
		}

		template<typename U>
		constexpr ox::Error field(StringViewCR, U) noexcept {
			++fields;
			return {};
		}

		template<typename U>
		constexpr ox::Error field(StringViewCR, U, std::size_t) noexcept {
			++fields;
			return {};
		}

		template<typename U, typename Handler>
		constexpr Error field(StringViewCR, Handler) {
			++fields;
			return {};
		}

		template<typename ...Args>
		constexpr Error fieldCString(Args&&...) noexcept {
			++fields;
			return {};
		}

		static constexpr auto opType() noexcept {
			return OpType::Reflect;
		}
};

}

namespace detail {
template<typename T>
[[nodiscard]]
consteval auto modelFieldCount() noexcept {
	auto a = std::allocator<T>();
	auto t = a.allocate(1);
	detail::FieldCounter<T> c;
	const auto err = model(&c, t);
	oxAssert(err, "Count failed");
	a.deallocate(t, 1);
	return c.fields;
}
}

template<typename T>
constexpr auto ModelFieldCount_v = detail::modelFieldCount<T>();

}
