# ShEx shapes for the Reiseplan vocabulary (https://reiseplan.app/ns#) — the
# ShExC equivalent of rp-shapes.ttl (SHACL). Both describe the same three
# resource shapes this app reads/writes in a Solid pod (see app/lib/rdf.ts):
#
#   rp:TripShape        one full itinerary (days -> activities), rp/trips.ttl
#   rp:TripStatusShape  set of "done" activity keys, rp/status.ttl
#   rp:TripLikesShape   per-activity like sets keyed by liker WebID, rp/likes.ttl
#
# Referenced from the embedded Application Capability document
# (app/lib/applicationCapability.ts) via ac:resourceType / ac:shape, alongside
# the SHACL version — a capability may link more than one shape.

PREFIX rp:     <https://reiseplan.app/ns#>
PREFIX schema: <https://schema.org/>
PREFIX xsd:    <http://www.w3.org/2001/XMLSchema#>
PREFIX ical:   <http://www.w3.org/2002/12/cal/ical#>
PREFIX geo:    <http://www.w3.org/2003/01/geo/wgs84_pos#>

# ==================== Trip ====================

rp:TripShape {
  rp:slug         xsd:string ;               # stable identifier, e.g. "prag"
  rp:kicker       xsd:string ;
  schema:name     xsd:string ;               # the trip's title
  rp:titleAccent  xsd:string ? ;
  rp:subtitle     xsd:string ;
  rp:accent       xsd:string ;               # theme key, e.g. "amber" or "emerald"
  rp:footer       xsd:string ;
  rp:startDate    xsd:date ? ;    # real calendar date of day 0; day N = startDate + N days
  rp:meta         @rp:MetaEntryShape * ;
  rp:info         @rp:InfoEntryShape * ;
  rp:day          @rp:DayShape + ;
}

rp:MetaEntryShape {
  rp:label xsd:string ;
  rp:value xsd:string ;
}

rp:InfoEntryShape {
  rp:label xsd:string ;
  rp:value xsd:string ;
}

rp:DayShape {
  rp:order      xsd:integer ;   # 0-based position — RDF doesn't preserve list order
  rp:label      xsd:string ;
  rp:weekday    xsd:string ;
  schema:name   xsd:string ;
  rp:subtitle   xsd:string ;
  rp:tag        xsd:string ;
  rp:activity   @rp:ActivityShape * ;
}

# Typed ical:Vevent; title/description use ical:summary/description rather than
# rp: terms. ical:dtstart is best-effort — only present when the trip has a
# startDate and rp:time contains a parseable HH:MM (see app/lib/rdf.ts:
# computeDtStart). rp:time itself is always kept as the free-form display
# label, since it's often approximate ("~14:00", "vor 9 Uhr").
rp:ActivityShape {
  a               [ical:Vevent] ;
  rp:id           xsd:string ? ;  # stable UUID, used as the events/ VEVENT export filename
  rp:order        xsd:integer ;
  rp:time         xsd:string ;   # free-form label, e.g. "09:30" or "~14:00" — not xsd:time
  ical:summary    xsd:string ;
  ical:description xsd:string ? ;
  ical:dtstart    xsd:dateTime ? ;
  ical:dtend      xsd:dateTime ? ;  # always dtstart + 30min (fixed default, no real end time in the source data)
  rp:badge        xsd:string ? ;
  rp:highlight    xsd:boolean ? ;
  geo:lat         xsd:decimal MININCLUSIVE -90 MAXINCLUSIVE 90 ? ;
  geo:long        xsd:decimal MININCLUSIVE -180 MAXINCLUSIVE 180 ? ;
  rp:mapsUrl      IRI ? ;        # link to the location on Google Maps or another map service
}

# ==================== TripStatus ====================
# rp:done values are "<tripSlug>:<dayIndex>:<activityIndex>" position keys, not IRIs.

rp:TripStatusShape {
  rp:done xsd:string * ;
}

# ==================== TripLikes ====================
# A liker can only ever add/remove their own WebID (enforced by the app, not the shape).

rp:TripLikesShape {
  rp:like @rp:LikeEntryShape * ;
}

rp:LikeEntryShape {
  rp:key   xsd:string ;   # same "<tripSlug>:<dayIndex>:<activityIndex>" key format
  rp:liker IRI ;          # the WebID of the person who liked this activity
}
