#pragma once

#include <yandex/maps/wiki/validator/common.h>
#include <yandex/maps/wiki/validator/check_context.h>

#include <map>
#include <vector>
#include <memory>

namespace maps {
namespace wiki {
namespace validator {

class ICheckPart
{
public:
    virtual void run(CheckContext* taskContext) = 0;

    virtual ~ICheckPart() = default;
};

using ICheckPartPtr = std::shared_ptr<ICheckPart>;

class CheckRegistry
{
public:
    struct CheckPartInfo
    {
        ICheckPartPtr runner;
        std::vector<TCategoryId> categoryDependencies;
    };

    using ModuleInfo = std::map<TCheckId, std::map<TCheckPartId, CheckPartInfo>>;

    template<class TCheckPart>
    void registerCheckPart(const std::string& moduleId, const TCheckId& checkId, const TCheckPartId& partId);

    const std::map<std::string, ModuleInfo>& modulesInfo() const { return modulesInfo_; }

private:
    std::map<std::string, ModuleInfo> modulesInfo_;
};

CheckRegistry& globalCheckRegistry();

template<typename TCheckPart>
struct CheckPartRegistrar
{
    CheckPartRegistrar(
            const std::string& moduleId,
            const TCheckId& checkId,
            const TCheckPartId& partId)
    {
        globalCheckRegistry().registerCheckPart<TCheckPart>(moduleId, checkId, partId);
    }
};

// Helper macros for check definition. Each macro should be followed by
// a code block. Check and part names should be valid C++ identifiers.
// VALIDATOR_CHECK_PART and VALIDATOR_SIMPLE_CHECK may not share a check name.

// Part name should be non-empty
#define VALIDATOR_CHECK_PART(check_name, part_name, ...) /* ... */

#define VALIDATOR_SIMPLE_CHECK(check_name, ...) /* ... */

} // namespace validator
} // namespace wiki
} // namespace maps

#define YANDEX_MAPS_WIKI_VALIDATOR_CHECK_INL
#include "check-inl.h"
#undef YANDEX_MAPS_WIKI_VALIDATOR_CHECK_INL
