@prefix : <https://ontology.inferal.com/modules/advertising-budget/> .
@prefix adm: <https://ontology.inferal.com/modules/advertising-measurement/> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix rng: <https://ontology.inferal.com/modules/range/> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

:BudgetShape
    a sh:NodeShape ;
    rdfs:label "budget shape" ;
    rdfs:comment "A budget figure is meaningless without its period, pacing, and scope, so all four parts are required. This is the constraint that stops a bare number being carried through as if it were comparable to another bare number." ;
    sh:targetClass :Budget ;
    sh:property [
        sh:path :budgetAmount ;
        sh:name "budget amount" ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:class adm:MonetaryAmount ;
    ] ;
    sh:property [
        sh:path :budgetPeriod ;
        sh:name "budget period" ;
        sh:description "Mandatory: a daily and a lifetime figure are different quantities, and without the period nothing can tell them apart." ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:class :BudgetPeriod ;
    ] ;
    sh:property [
        sh:path :budgetDeliveryMethod ;
        sh:name "delivery method" ;
        sh:description "Mandatory: pacing changes what a partial-period spend figure means." ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:class :DeliveryMethod ;
    ] ;
    sh:property [
        sh:path :appliesToScope ;
        sh:name "applies to scope" ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:class :BudgetScope ;
    ] ;
    sh:property [
        sh:path :effectiveWindow ;
        sh:name "effective window" ;
        sh:description "Absent for a standing allowance with no defined flight." ;
        sh:maxCount 1 ;
        sh:class rng:Range ;
    ] .

:BudgetScopeShape
    a sh:NodeShape ;
    rdfs:label "budget scope shape" ;
    rdfs:comment "A scope must name at least one covered entity. A scope covering several is shared, and the sharing flag must agree with what is enumerated where both are present." ;
    sh:targetClass :BudgetScope ;
    sh:property [
        sh:path :coversEntity ;
        sh:name "covers entity" ;
        sh:description "Repeatable and optional. More than one means the allowance is pooled and per-entity spend cannot be attributed. Absence means the covered set is unenumerated rather than empty, which is how one provider reports a shared budget: a flag and a reference count, with nothing named." ;
        sh:nodeKind sh:IRI ;
    ] ;
    sh:property [
        sh:path :coveredEntityCount ;
        sh:name "covered entity count" ;
        sh:description "How many entities the scope covers, where the provider reports a count instead of a list." ;
        sh:maxCount 1 ;
        sh:datatype xsd:integer ;
        sh:minInclusive 1 ;
    ] ;
    sh:property [
        sh:path :sharedAcrossEntities ;
        sh:name "shared across entities" ;
        sh:maxCount 1 ;
        sh:datatype xsd:boolean ;
    ] .

:SpendCapShape
    a sh:NodeShape ;
    rdfs:label "spend cap shape" ;
    rdfs:comment "A cap states an amount, the period it applies over, and what it constrains. It carries no delivery method, because a ceiling does not pace." ;
    sh:targetClass :SpendCap ;
    sh:property [
        sh:path :capAmount ;
        sh:name "cap amount" ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:class adm:MonetaryAmount ;
    ] ;
    sh:property [
        sh:path :capPeriod ;
        sh:name "cap period" ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:class :BudgetPeriod ;
    ] ;
    sh:property [
        sh:path :constrainsScope ;
        sh:name "constrains scope" ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:class :BudgetScope ;
    ] ;
    sh:property [
        sh:path :budgetDeliveryMethod ;
        sh:name "delivery method" ;
        sh:description "Forbidden: a ceiling constrains delivery without directing it, so pacing does not apply." ;
        sh:maxCount 0 ;
    ] .

:BudgetPeriodShape
    a sh:NodeShape ;
    rdfs:label "budget period shape" ;
    rdfs:comment "Periods must be resolvable IRIs so a comparability rule can branch on identity rather than on a label." ;
    sh:targetClass :BudgetPeriod ;
    sh:nodeKind sh:IRI .

:DeliveryMethodShape
    a sh:NodeShape ;
    rdfs:label "delivery method shape" ;
    rdfs:comment "Delivery methods must be resolvable IRIs for the same reason as periods." ;
    sh:targetClass :DeliveryMethod ;
    sh:nodeKind sh:IRI .
