#pragma once

#include <cstddef>
#include <cstdint>
#include <map>
#include <set>
#include <string>
#include <string_view>
#include <vector>

namespace ta::features::quests::contracts
{
    enum class QuestCategory
    {
        Main,
        Side,
        Operational,
        Unclassified
    };

    enum class QuestAction
    {
        CompleteQuest,
        SkipTask
    };

    [[nodiscard]] constexpr std::string_view to_string(const QuestAction action) noexcept
    {
        return action == QuestAction::SkipTask ? "Skip" : "Complete quest";
    }

    struct QuestStatus
    {
        static constexpr int Started = 2;
        static constexpr int Completed = 3;
    };

    struct QuestConditionEntry
    {
        std::string id;
        std::string text;
        int current = 0;
        int required = 0;
        bool completed = false;
        int depth = 0;

        bool operator==(const QuestConditionEntry&) const = default;
    };

    struct QuestEntry
    {
        std::string id;
        std::string name;
        std::string trader_id;
        std::string trader_name;
        QuestCategory category = QuestCategory::Unclassified;
        std::vector<QuestConditionEntry> conditions;

        bool operator==(const QuestEntry&) const = default;
    };

    using QuestConditionSelection = std::map<std::string, std::set<std::string>>;

    struct PendingQuestCommands
    {
        std::set<std::string> complete_quest;
        std::set<std::string> skip_task;
        QuestConditionSelection complete_conditions;

        [[nodiscard]] bool contains(const std::string& id) const
        {
            return complete_quest.contains(id) ||
                   skip_task.contains(id) ||
                   complete_conditions.contains(id);
        }
    };

    struct QuestCommandBatch
    {
        QuestAction action = QuestAction::CompleteQuest;
        std::set<std::string> quest_ids;
        QuestConditionSelection condition_ids;
        std::uint64_t trace_id = 0;

        [[nodiscard]] std::size_t selection_count() const noexcept
        {
            std::size_t count = quest_ids.size();
            for (const auto& [_, ids] : condition_ids)
                count += ids.size();
            return count;
        }

        [[nodiscard]] bool empty() const noexcept
        {
            return quest_ids.empty() && condition_ids.empty();
        }
    };

    struct QuestListSnapshot
    {
        std::vector<QuestEntry> quests;

        bool operator==(const QuestListSnapshot&) const = default;
    };
}
