/*********************************************************************
 * \file   Version.hpp
 *
 * \author Romain BOULLARD
 * \date   October 2025
 *********************************************************************/
#ifndef BIGFOOT_UTILS_VERSION_HPP
#define BIGFOOT_UTILS_VERSION_HPP
#include <Utils/Caster.hpp>
#include <Utils/TargetMacros.h>

#include <cstdint>
#include <format>
#include <string>

namespace Bigfoot
{
class Version
{
  public:
    Version() = default;

    /**
     * Constructor.
     *
     * \param p_combined The combined version.
     */
    explicit constexpr Version(const std::uint32_t p_combined):
        m_combined(p_combined)
    {
    }

    /**
     * Constructor.
     *
     * \param p_major Major
     * \param p_minor Minor
     * \param p_patch Patch
     */
    constexpr Version(const std::uint8_t p_major, const std::uint8_t p_minor, const std::uint8_t p_patch):
        m_combined((p_major << 16) | (p_minor << 8) | p_patch)
    {
    }

    Version(const Version& p_version) = default;
    Version(Version&& p_version) = default;

    ~Version() = default;

    /**
     * Get the major part of the version.
     *
     * \return The major part of the version.
     */
    [[nodiscard]]
    constexpr std::uint8_t GetMajor() const
    {
        constexpr std::uint32_t mask = 0b00000000111111110000000000000000;

        return static_cast<std::uint8_t>((m_combined & mask) >> 16);
    }

    /**
     * Get the minor part of the version.
     *
     * \return The minor part of the version.
     */
    [[nodiscard]]
    constexpr std::uint8_t GetMinor() const
    {
        constexpr std::uint32_t mask = 0b00000000000000001111111100000000;

        return static_cast<std::uint8_t>((m_combined & mask) >> 8);
    }

    /**
     * Get the patch part of the version.
     *
     * \return The patch part of the version.
     */
    [[nodiscard]]
    constexpr std::uint8_t GetPatch() const
    {
        constexpr std::uint32_t mask = 0b00000000000000000000000011111111;

        return static_cast<std::uint8_t>(m_combined & mask);
    }

    /**
     * Gets the raw Version
     *
     * \return the raw version
     */
    [[nodiscard]]
    constexpr std::uint32_t Raw() const
    {
        return m_combined;
    }

    /**
     * Gets the string representation of the Version
     *
     * \return The string
     */
    [[nodiscard]]
    std::string ToString() const;

    constexpr Version& operator=(const Version& p_version) = default;
    constexpr Version& operator=(Version&& p_version) = default;

    [[nodiscard]]
    constexpr auto operator<=>(const Version& p_version) const = default;

  private:
    /**
     * The combined version.
     */
    std::uint32_t m_combined = 0;
};
}   // namespace Bigfoot

/****************************************************************************************/

#if defined BIGFOOT_NOT_OPTIMIZED
template<>
struct std::formatter<Bigfoot::Version>
{
    template<typename ParseContext>
    constexpr auto parse(ParseContext& p_context)
    {
        return p_context.begin();
    }

    template<typename FormatContext>
    auto format(const Bigfoot::Version& p_version, FormatContext& p_context) const
    {
        return std::format_to(p_context.out(), "{}", p_version.ToString());
    }
};
#endif
#endif
