#include "adapters/eft/quests/conditions/QuestConditionService.h"

#include "adapters/eft/quests/QuestCompletionPlan.h"
#include "adapters/eft/quests/conditions/QuestConditionExecutor.h"
#include "adapters/eft/quests/conditions/QuestConditionGraph.h"
#include "adapters/il2cpp/ManagedRuntime.h"
#include "foundation/diagnostics/OnceLogger.h"

namespace ta::adapters::eft::quests
{
    QuestConditionService::ConditionEntryList QuestConditionService::collect_condition_entries(
        ta::adapters::il2cpp::Il2CppObjectInstance& quest,
        ta::adapters::il2cpp::Il2CppObjectInstance main_player)
    {
        ConditionEntryList result;
        const QuestConditionGraph graph = QuestConditionGraph::build(quest, main_player);
        result.reserve(graph.nodes().size());
        for (const QuestConditionNode& node : graph.nodes())
        {
            if (node.id_string.empty() || node.text.empty())
                continue;
            result.push_back({
                node.id_string,
                node.text,
                node.current,
                node.target,
                node.completed,
                node.depth
            });
        }
        return result;
    }

    void QuestConditionService::complete_all_conditions(
        ta::adapters::il2cpp::Il2CppObjectInstance& quest,
        ta::adapters::il2cpp::Il2CppObjectInstance main_player)
    {
        const QuestConditionGraph graph = QuestConditionGraph::build(quest, main_player);
        QuestConditionExecutor::execute(
            quest, main_player, QuestCompletionPlanner::complete_all(graph));
    }

    void QuestConditionService::complete_selected_conditions(
        ta::adapters::il2cpp::Il2CppObjectInstance& quest,
        ta::adapters::il2cpp::Il2CppObjectInstance main_player,
        const std::set<std::string>& selected_ids)
    {
        if (selected_ids.empty())
            return;
        const QuestConditionGraph graph = QuestConditionGraph::build(quest, main_player);
        QuestConditionExecutor::execute(
            quest, main_player, QuestCompletionPlanner::complete_selected(graph, selected_ids));
    }

    void QuestConditionService::set_quest_status_completed(
        ta::adapters::il2cpp::Il2CppObjectInstance& quest,
        const std::string& quest_id)
    {
        Il2CppObject* quest_object = quest.get_instance();
        const auto method = ta::adapters::il2cpp::ManagedRuntime::method(
            quest_object ? quest_object->klass : nullptr,
            "SetStatus",
            3,
            ta::adapters::il2cpp::LookupPolicy::IncludeBaseClasses);
        if (!method)
        {
            ta::foundation::diagnostics::OnceLogger::warn(
                "QUEST", "quest-set-status:" + quest_id,
                "Quest method missing: SetStatus for " + quest_id);
            return;
        }

        reinterpret_cast<void(*)(Il2CppObject*, int, bool, bool)>(
            method.value()->methodPointer)(
                quest_object,
                ta::features::quests::contracts::QuestStatus::Completed,
                true,
                false);
    }
}
