#pragma once

#include <cstddef>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>

#include "features/quests/contracts/QuestTypes.h"

namespace ta::presentation::pages::quests
{
    class QuestSelectionModel final
    {
    public:
        using Entry = ta::features::quests::contracts::QuestEntry;
        using Condition = ta::features::quests::contracts::QuestConditionEntry;
        using Snapshot = ta::features::quests::contracts::QuestListSnapshot;
        using ConditionSelection = ta::features::quests::contracts::QuestConditionSelection;

        void refresh(std::shared_ptr<const Snapshot> snapshot);

        [[nodiscard]] int& category_filter() noexcept { return category_filter_; }
        [[nodiscard]] int category_filter() const noexcept { return category_filter_; }

        [[nodiscard]] bool selected(const Entry& quest) const;
        void set_selected(const Entry& quest, bool selected);
        void clear_selection() noexcept;
        [[nodiscard]] std::size_t selected_count() const noexcept;
        [[nodiscard]] const std::set<std::string>& selected_ids() const noexcept;

        [[nodiscard]] bool condition_selected(const Entry& quest, const Condition& condition) const;
        void set_condition_selected(const Entry& quest, const Condition& condition, bool selected);
        void select_incomplete_conditions(const Entry& quest);
        void clear_condition_selection(const Entry& quest);
        [[nodiscard]] std::size_t selected_condition_count() const noexcept;
        [[nodiscard]] std::size_t selected_condition_count(const Entry& quest) const noexcept;
        [[nodiscard]] std::size_t total_selection_count() const noexcept;
        [[nodiscard]] const ConditionSelection& selected_condition_ids() const noexcept;

        void select_visible(bool selected = true);

        [[nodiscard]] const std::vector<const Entry*>& visible() const noexcept;

        void select_detail(const std::string& id);
        [[nodiscard]] const std::string& selected_detail_id() const noexcept;
        [[nodiscard]] const Entry* selected_detail() const noexcept;

    private:
        void prune_selection();
        void rebuild_filter();
        [[nodiscard]] bool matches(const Entry& quest) const;
        void ensure_visible_detail();

        std::set<std::string> selected_ids_;
        ConditionSelection selected_condition_ids_;
        std::shared_ptr<const Snapshot> snapshot_;
        int category_filter_ = 0;
        std::string selected_detail_id_;

        std::shared_ptr<const Snapshot> filtered_snapshot_;
        int filtered_category_ = -1;
        std::vector<const Entry*> visible_;
    };
}
