module glued.annotations.validation_impl;

import std.meta: staticMap;
import std.traits: getUDAs;

import glued.annotations.core_impl: getExplicitAnnotations, expandToData;
import glued.annotations.core_annotations: CheckedBy;

template performCheck(alias AnnotatedTarget){ // e.g. newly declared interface
    template getCheckers(alias constraint){
        alias getCheckers = staticMap!(expandToData, getUDAs!(typeof(constraint), CheckedBy));
    }

    template on(alias AnnotationOccurence){ //e.g. Component() (notice that it's value, not type)
        alias constraints = getExplicitAnnotations!(typeof(AnnotationOccurence)); // e.g. Repeatable(ONCE) (ditto); todo: maybe checked?
        static foreach (constraint; constraints){ // Repeatable(...) annotated with CheckedBy!(...)
            static foreach (checker; getCheckers!(constraint)){
                import std.conv;
                import std.traits;
                //todo message should be configurable next to CheckedBy
                static assert(checker.check!(AnnotatedTarget, AnnotationOccurence, constraint)(), "Constraint "~to!string(constraint)~" for annotation "~to!string(AnnotationOccurence)~" on target "~fullyQualifiedName!(AnnotatedTarget));
            }
        }
        alias on = AnnotationOccurence;
    }
}