// WARNING: This file is automatically generated. Any changes will be lost.
#include "twitch-eventsub-ws/payloads/automod-message.hpp"

#include "twitch-eventsub-ws/chrono.hpp"  // IWYU pragma: keep
#include "twitch-eventsub-ws/detail/errors.hpp"
#include "twitch-eventsub-ws/detail/variant.hpp"  // IWYU pragma: keep

#include <boost/json.hpp>

namespace chatterino::eventsub::lib::automod {

boost::json::result_for<Boundary, boost::json::value>::type tag_invoke(
    boost::json::try_value_to_tag<Boundary> /* tag */,
    const boost::json::value &jvRoot)
{
    if (!jvRoot.is_object())
    {
        EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject);
    }
    const auto &root = jvRoot.get_object();

    static_assert(std::is_trivially_copyable_v<std::remove_reference_t<
                      decltype(std::declval<Boundary>().startPos)>>);
    const auto *jvstartPos = root.if_contains("start_pos");
    if (jvstartPos == nullptr)
    {
        EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
    }

    auto startPos = boost::json::try_value_to<int>(*jvstartPos);

    if (startPos.has_error())
    {
        return startPos.error();
    }

    static_assert(std::is_trivially_copyable_v<std::remove_reference_t<
                      decltype(std::declval<Boundary>().endPos)>>);
    const auto *jvendPos = root.if_contains("end_pos");
    if (jvendPos == nullptr)
    {
        EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
    }

    auto endPos = boost::json::try_value_to<int>(*jvendPos);

    if (endPos.has_error())
    {
        return endPos.error();
    }

    return Boundary{
        .startPos = startPos.value(),
        .endPos = endPos.value(),
    };
}

boost::json::result_for<AutomodReason, boost::json::value>::type tag_invoke(
    boost::json::try_value_to_tag<AutomodReason> /* tag */,
    const boost::json::value &jvRoot)
{
    if (!jvRoot.is_object())
    {
        EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject);
    }
    const auto &root = jvRoot.get_object();

    const auto *jvcategory = root.if_contains("category");
    if (jvcategory == nullptr)
    {
        EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
    }

    auto category = boost::json::try_value_to<String>(*jvcategory);

    if (category.has_error())
    {
        return category.error();
    }

    static_assert(std::is_trivially_copyable_v<std::remove_reference_t<
                      decltype(std::declval<AutomodReason>().level)>>);
    const auto *jvlevel = root.if_contains("level");
    if (jvlevel == nullptr)
    {
        EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
    }

    auto level = boost::json::try_value_to<int>(*jvlevel);

    if (level.has_error())
    {
        return level.error();
    }

    std::vector<Boundary> vboundaries;
    const auto *jvboundaries = root.if_contains("boundaries");
    if (jvboundaries != nullptr && !jvboundaries->is_null())
    {
        auto boundaries =
            boost::json::try_value_to<std::vector<Boundary>>(*jvboundaries);
        if (boundaries.has_error())
        {
            return boundaries.error();
        }
        else
        {
            vboundaries = std::move(boundaries.value());
        }
    }

    return AutomodReason{
        .category = std::move(category.value()),
        .level = level.value(),
        .boundaries = std::move(vboundaries),
    };
}

boost::json::result_for<FoundTerm, boost::json::value>::type tag_invoke(
    boost::json::try_value_to_tag<FoundTerm> /* tag */,
    const boost::json::value &jvRoot)
{
    if (!jvRoot.is_object())
    {
        EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject);
    }
    const auto &root = jvRoot.get_object();

    const auto *jvtermID = root.if_contains("term_id");
    if (jvtermID == nullptr)
    {
        EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
    }

    auto termID = boost::json::try_value_to<std::string>(*jvtermID);

    if (termID.has_error())
    {
        return termID.error();
    }

    static_assert(std::is_trivially_copyable_v<std::remove_reference_t<
                      decltype(std::declval<FoundTerm>().boundary)>>);
    const auto *jvboundary = root.if_contains("boundary");
    if (jvboundary == nullptr)
    {
        EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
    }

    auto boundary = boost::json::try_value_to<Boundary>(*jvboundary);

    if (boundary.has_error())
    {
        return boundary.error();
    }

    const auto *jvownerBroadcasterUserID =
        root.if_contains("owner_broadcaster_user_id");
    if (jvownerBroadcasterUserID == nullptr)
    {
        EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
    }

    auto ownerBroadcasterUserID =
        boost::json::try_value_to<std::string>(*jvownerBroadcasterUserID);

    if (ownerBroadcasterUserID.has_error())
    {
        return ownerBroadcasterUserID.error();
    }

    const auto *jvownerBroadcasterUserLogin =
        root.if_contains("owner_broadcaster_user_login");
    if (jvownerBroadcasterUserLogin == nullptr)
    {
        EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
    }

    auto ownerBroadcasterUserLogin =
        boost::json::try_value_to<std::string>(*jvownerBroadcasterUserLogin);

    if (ownerBroadcasterUserLogin.has_error())
    {
        return ownerBroadcasterUserLogin.error();
    }

    const auto *jvownerBroadcasterUserName =
        root.if_contains("owner_broadcaster_user_name");
    if (jvownerBroadcasterUserName == nullptr)
    {
        EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
    }

    auto ownerBroadcasterUserName =
        boost::json::try_value_to<std::string>(*jvownerBroadcasterUserName);

    if (ownerBroadcasterUserName.has_error())
    {
        return ownerBroadcasterUserName.error();
    }

    return FoundTerm{
        .termID = std::move(termID.value()),
        .boundary = boundary.value(),
        .ownerBroadcasterUserID = std::move(ownerBroadcasterUserID.value()),
        .ownerBroadcasterUserLogin =
            std::move(ownerBroadcasterUserLogin.value()),
        .ownerBroadcasterUserName = std::move(ownerBroadcasterUserName.value()),
    };
}

boost::json::result_for<BlockedTermReason, boost::json::value>::type tag_invoke(
    boost::json::try_value_to_tag<BlockedTermReason> /* tag */,
    const boost::json::value &jvRoot)
{
    if (!jvRoot.is_object())
    {
        EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject);
    }
    const auto &root = jvRoot.get_object();

    std::vector<FoundTerm> vtermsFound;
    const auto *jvtermsFound = root.if_contains("terms_found");
    if (jvtermsFound != nullptr && !jvtermsFound->is_null())
    {
        auto termsFound =
            boost::json::try_value_to<std::vector<FoundTerm>>(*jvtermsFound);
        if (termsFound.has_error())
        {
            return termsFound.error();
        }
        else
        {
            vtermsFound = std::move(termsFound.value());
        }
    }

    return BlockedTermReason{
        .termsFound = std::move(vtermsFound),
    };
}

}  // namespace chatterino::eventsub::lib::automod
