# FHIR Patient Management SPARQL Queries
# Collection of queries for patient demographics, observations, medications, conditions

PREFIX fhir: <http://hl7.org/fhir/>
PREFIX fhir-ontology: <http://ggen.io/ontology/fhir#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

# ============================================================================
# Query 1: Extract Patient Demographics
# ============================================================================
# TEMPLATE: patient-demographics
# DESCRIPTION: Retrieve complete patient demographic information

SELECT ?patientId ?mrn ?firstName ?lastName ?gender ?birthDate ?phone ?email ?city ?state
WHERE {
  ?patient a fhir-ontology:Patient ;
           fhir-ontology:identifier ?mrn ;
           fhir-ontology:active true ;
           fhir-ontology:gender ?gender ;
           fhir-ontology:birthDate ?birthDate .

  ?patient fhir-ontology:name ?name .
  ?name fhir-ontology:given ?firstName ;
        fhir-ontology:family ?lastName .

  OPTIONAL {
    ?patient fhir-ontology:telecom ?telecom .
    ?telecom fhir-ontology:system "phone" ;
             fhir-ontology:value ?phone .
  }

  OPTIONAL {
    ?patient fhir-ontology:telecom ?emailContact .
    ?emailContact fhir-ontology:system "email" ;
                  fhir-ontology:value ?email .
  }

  OPTIONAL {
    ?patient fhir-ontology:address ?address .
    ?address fhir-ontology:city ?city ;
             fhir-ontology:state ?state .
  }

  BIND(STRAFTER(STR(?patient), "#") AS ?patientId)
}
ORDER BY ?lastName ?firstName

# ============================================================================
# Query 2: Generate FHIR Bundle for Patient
# ============================================================================
# TEMPLATE: patient-bundle
# DESCRIPTION: Create FHIR Bundle with all resources for a patient

CONSTRUCT {
  ?patient a fhir-ontology:Patient ;
           fhir-ontology:identifier ?mrn ;
           fhir-ontology:name ?name ;
           fhir-ontology:gender ?gender ;
           fhir-ontology:birthDate ?birthDate .

  ?observation a fhir-ontology:Observation ;
               fhir-ontology:subject ?patient ;
               fhir-ontology:observationCode ?obsCode ;
               fhir-ontology:effectiveDateTime ?obsDate ;
               fhir-ontology:valueQuantity ?obsValue .

  ?medication a fhir-ontology:MedicationRequest ;
              fhir-ontology:subject ?patient ;
              fhir-ontology:medication ?medCode ;
              fhir-ontology:authoredOn ?medDate .

  ?condition a fhir-ontology:Condition ;
             fhir-ontology:subject ?patient ;
             fhir-ontology:conditionCode ?condCode ;
             fhir-ontology:clinicalStatus ?clinicalStatus .
}
WHERE {
  ?patient a fhir-ontology:Patient ;
           fhir-ontology:identifier ?mrn .
  FILTER(?mrn = "{{MRN}}")

  ?patient fhir-ontology:name ?name ;
           fhir-ontology:gender ?gender ;
           fhir-ontology:birthDate ?birthDate .

  OPTIONAL {
    ?observation a fhir-ontology:Observation ;
                 fhir-ontology:subject ?patient ;
                 fhir-ontology:observationCode ?obsCode ;
                 fhir-ontology:effectiveDateTime ?obsDate ;
                 fhir-ontology:valueQuantity ?obsValue .
  }

  OPTIONAL {
    ?medication a fhir-ontology:MedicationRequest ;
                fhir-ontology:subject ?patient ;
                fhir-ontology:medication ?medCode ;
                fhir-ontology:authoredOn ?medDate .
  }

  OPTIONAL {
    ?condition a fhir-ontology:Condition ;
               fhir-ontology:subject ?patient ;
               fhir-ontology:conditionCode ?condCode ;
               fhir-ontology:clinicalStatus ?clinicalStatus .
  }
}

# ============================================================================
# Query 3: Query Observations by LOINC Code and Date Range
# ============================================================================
# TEMPLATE: observations-by-code-date
# DESCRIPTION: Filter observations by LOINC code and date range

SELECT ?patientMRN ?patientName ?observationDate ?loincCode ?loincDisplay ?value ?unit ?interpretation
WHERE {
  ?patient a fhir-ontology:Patient ;
           fhir-ontology:identifier ?patientMRN ;
           fhir-ontology:name ?nameObj .
  ?nameObj fhir-ontology:family ?lastName ;
           fhir-ontology:given ?firstName .
  BIND(CONCAT(?firstName, " ", ?lastName) AS ?patientName)

  ?observation a fhir-ontology:Observation ;
               fhir-ontology:subject ?patient ;
               fhir-ontology:status "final" ;
               fhir-ontology:effectiveDateTime ?observationDate ;
               fhir-ontology:observationCode ?codeableConcept .

  ?codeableConcept fhir-ontology:coding ?coding .
  ?coding fhir-ontology:systemUri <http://loinc.org> ;
          fhir-ontology:code ?loincCode ;
          fhir-ontology:display ?loincDisplay .

  FILTER(?loincCode = "{{LOINC_CODE}}")
  FILTER(?observationDate >= "{{START_DATE}}"^^xsd:dateTime && ?observationDate <= "{{END_DATE}}"^^xsd:dateTime)

  ?observation fhir-ontology:valueQuantity ?quantity .
  ?quantity fhir-ontology:quantityValue ?value ;
            fhir-ontology:unit ?unit .

  OPTIONAL {
    ?observation fhir-ontology:interpretation ?interpConcept .
    ?interpConcept fhir-ontology:text ?interpretation .
  }
}
ORDER BY ?patientMRN ?observationDate

# ============================================================================
# Query 4: Extract Medication Adherence Data
# ============================================================================
# TEMPLATE: medication-adherence
# DESCRIPTION: Calculate medication adherence from requests and statements

SELECT ?patientMRN ?medicationName ?prescribedDate ?dosage ?frequency ?refills ?lastDispensed ?adherenceRate
WHERE {
  ?patient a fhir-ontology:Patient ;
           fhir-ontology:identifier ?patientMRN .

  ?medRequest a fhir-ontology:MedicationRequest ;
              fhir-ontology:subject ?patient ;
              fhir-ontology:status "active" ;
              fhir-ontology:medication ?medConcept ;
              fhir-ontology:authoredOn ?prescribedDate .

  ?medConcept fhir-ontology:coding ?medCoding .
  ?medCoding fhir-ontology:display ?medicationName .

  OPTIONAL {
    ?medRequest fhir-ontology:dosageInstruction ?dosage .
    ?dosage fhir-ontology:timing ?timing .
    # Extract frequency from timing
  }

  # Calculate adherence based on dispensing records
  # This would join with MedicationStatement or dispense events
}
ORDER BY ?patientMRN ?prescribedDate DESC

# ============================================================================
# Query 5: Generate HL7 FHIR JSON for Patient
# ============================================================================
# TEMPLATE: patient-to-fhir-json
# DESCRIPTION: Transform RDF patient data to FHIR JSON structure

SELECT ?json
WHERE {
  ?patient a fhir-ontology:Patient ;
           fhir-ontology:identifier ?mrn ;
           fhir-ontology:name ?name ;
           fhir-ontology:gender ?gender ;
           fhir-ontology:birthDate ?birthDate .

  FILTER(?mrn = "{{MRN}}")

  ?name fhir-ontology:family ?family ;
        fhir-ontology:given ?given .

  BIND(CONCAT('{',
    '"resourceType": "Patient",',
    '"identifier": [{"value": "', ?mrn, '"}],',
    '"name": [{"family": "', ?family, '", "given": ["', ?given, '"]}],',
    '"gender": "', ?gender, '",',
    '"birthDate": "', STR(?birthDate), '"',
    '}') AS ?json)
}

# ============================================================================
# Query 6: Privacy Filtering with Consent
# ============================================================================
# TEMPLATE: privacy-filter
# DESCRIPTION: Filter patient data based on consent and security labels

SELECT ?resource ?resourceType ?accessLevel
WHERE {
  ?resource a ?resourceType ;
            fhir-ontology:subject ?patient .

  ?patient fhir-ontology:identifier "{{PATIENT_MRN}}" .

  # Check consent provisions
  OPTIONAL {
    ?consent a fhir-ontology:Consent ;
             fhir-ontology:subject ?patient ;
             fhir-ontology:provision ?provision .
    ?provision fhir-ontology:provisionType ?provisionType .
  }

  # Check security labels
  OPTIONAL {
    ?resource fhir-ontology:securityLabel ?secLabel .
    ?secLabel fhir-ontology:code ?accessLevel .
  }

  # Filter based on requester role
  FILTER(?provisionType = "permit" || !BOUND(?provisionType))
  FILTER(?accessLevel IN ("N", "R") || !BOUND(?accessLevel))
}

# ============================================================================
# Query 7: Vital Signs Trend Analysis
# ============================================================================
# TEMPLATE: vital-signs-trend
# DESCRIPTION: Analyze vital signs trends over time

SELECT ?patientMRN ?vitalSign ?observationDate ?value ?unit ?trend
WHERE {
  ?patient a fhir-ontology:Patient ;
           fhir-ontology:identifier ?patientMRN .

  ?observation a fhir-ontology:Observation ;
               fhir-ontology:subject ?patient ;
               fhir-ontology:category ?category ;
               fhir-ontology:observationCode ?code ;
               fhir-ontology:effectiveDateTime ?observationDate ;
               fhir-ontology:valueQuantity ?quantity .

  ?category fhir-ontology:coding ?catCoding .
  ?catCoding fhir-ontology:code "vital-signs" .

  ?code fhir-ontology:coding ?coding .
  ?coding fhir-ontology:display ?vitalSign .

  ?quantity fhir-ontology:quantityValue ?value ;
            fhir-ontology:unit ?unit .

  # Calculate trend compared to previous reading
  # This would require window functions or multiple queries
}
ORDER BY ?patientMRN ?vitalSign ?observationDate

# ============================================================================
# Query 8: Active Conditions Summary
# ============================================================================
# TEMPLATE: active-conditions
# DESCRIPTION: List all active conditions for patients

SELECT ?patientMRN ?patientName ?conditionCode ?conditionName ?onsetDate ?severity
WHERE {
  ?patient a fhir-ontology:Patient ;
           fhir-ontology:identifier ?patientMRN ;
           fhir-ontology:name ?nameObj .
  ?nameObj fhir-ontology:family ?lastName ;
           fhir-ontology:given ?firstName .
  BIND(CONCAT(?firstName, " ", ?lastName) AS ?patientName)

  ?condition a fhir-ontology:Condition ;
             fhir-ontology:subject ?patient ;
             fhir-ontology:clinicalStatus ?status ;
             fhir-ontology:conditionCode ?condConcept .

  ?status fhir-ontology:coding ?statusCoding .
  ?statusCoding fhir-ontology:code "active" .

  ?condConcept fhir-ontology:coding ?condCoding .
  ?condCoding fhir-ontology:code ?conditionCode ;
              fhir-ontology:display ?conditionName .

  OPTIONAL {
    ?condition fhir-ontology:onsetDateTime ?onsetDate .
  }

  OPTIONAL {
    ?condition fhir-ontology:severity ?sevConcept .
    ?sevConcept fhir-ontology:text ?severity .
  }
}
ORDER BY ?patientMRN ?onsetDate DESC

# ============================================================================
# Query 9: Encounter History
# ============================================================================
# TEMPLATE: encounter-history
# DESCRIPTION: Retrieve patient encounter history

SELECT ?patientMRN ?encounterDate ?encounterType ?encounterClass ?practitionerName
WHERE {
  ?patient a fhir-ontology:Patient ;
           fhir-ontology:identifier ?patientMRN .

  ?encounter a fhir-ontology:Encounter ;
             fhir-ontology:subject ?patient ;
             fhir-ontology:encounterClass ?class ;
             fhir-ontology:period ?period .

  ?class fhir-ontology:code ?encounterClass .

  ?period fhir-ontology:start ?encounterDate .

  OPTIONAL {
    ?encounter fhir-ontology:type ?typeConcept .
    ?typeConcept fhir-ontology:text ?encounterType .
  }

  OPTIONAL {
    ?encounter fhir-ontology:participant ?participant .
    ?participant fhir-ontology:individual ?practitioner .
    ?practitioner fhir-ontology:name ?practName .
    ?practName fhir-ontology:text ?practitionerName .
  }
}
ORDER BY ?patientMRN ?encounterDate DESC

# ============================================================================
# Query 10: Lab Results with Reference Ranges
# ============================================================================
# TEMPLATE: lab-results-reference
# DESCRIPTION: Lab results with normal range comparison

SELECT ?patientMRN ?testName ?testDate ?value ?unit ?lowRange ?highRange ?status
WHERE {
  ?patient a fhir-ontology:Patient ;
           fhir-ontology:identifier ?patientMRN .

  ?observation a fhir-ontology:Observation ;
               fhir-ontology:subject ?patient ;
               fhir-ontology:category ?category ;
               fhir-ontology:observationCode ?code ;
               fhir-ontology:effectiveDateTime ?testDate ;
               fhir-ontology:valueQuantity ?quantity .

  ?category fhir-ontology:coding ?catCoding .
  ?catCoding fhir-ontology:code "laboratory" .

  ?code fhir-ontology:text ?testName .

  ?quantity fhir-ontology:quantityValue ?value ;
            fhir-ontology:unit ?unit .

  OPTIONAL {
    ?observation fhir-ontology:referenceRange ?refRange .
    ?refRange fhir-ontology:low ?lowQty ;
              fhir-ontology:high ?highQty .
    ?lowQty fhir-ontology:quantityValue ?lowRange .
    ?highQty fhir-ontology:quantityValue ?highRange .
  }

  BIND(IF(?value < ?lowRange, "LOW",
       IF(?value > ?highRange, "HIGH", "NORMAL")) AS ?status)
}
ORDER BY ?patientMRN ?testDate DESC

# ============================================================================
# Query 11: Patient Search by Demographics
# ============================================================================
# TEMPLATE: patient-search
# DESCRIPTION: Search patients by name, DOB, or identifier

SELECT ?patientId ?mrn ?fullName ?gender ?birthDate ?phone
WHERE {
  ?patient a fhir-ontology:Patient ;
           fhir-ontology:identifier ?mrn ;
           fhir-ontology:name ?name ;
           fhir-ontology:gender ?gender ;
           fhir-ontology:birthDate ?birthDate .

  ?name fhir-ontology:family ?lastName ;
        fhir-ontology:given ?firstName .
  BIND(CONCAT(?firstName, " ", ?lastName) AS ?fullName)

  OPTIONAL {
    ?patient fhir-ontology:telecom ?telecom .
    ?telecom fhir-ontology:system "phone" ;
             fhir-ontology:value ?phone .
  }

  FILTER(
    REGEX(?lastName, "{{LAST_NAME}}", "i") ||
    REGEX(?firstName, "{{FIRST_NAME}}", "i") ||
    ?mrn = "{{MRN}}" ||
    ?birthDate = "{{BIRTH_DATE}}"^^xsd:date
  )

  BIND(STRAFTER(STR(?patient), "#") AS ?patientId)
}
ORDER BY ?lastName ?firstName

# ============================================================================
# Query 12: Medication Interactions Check
# ============================================================================
# TEMPLATE: medication-interactions
# DESCRIPTION: Check for potential medication interactions

SELECT ?patientMRN ?medication1 ?medication2 ?interactionSeverity ?interactionDescription
WHERE {
  ?patient a fhir-ontology:Patient ;
           fhir-ontology:identifier ?patientMRN .

  ?medRequest1 a fhir-ontology:MedicationRequest ;
               fhir-ontology:subject ?patient ;
               fhir-ontology:status "active" ;
               fhir-ontology:medication ?medConcept1 .

  ?medRequest2 a fhir-ontology:MedicationRequest ;
               fhir-ontology:subject ?patient ;
               fhir-ontology:status "active" ;
               fhir-ontology:medication ?medConcept2 .

  FILTER(?medRequest1 != ?medRequest2)

  ?medConcept1 fhir-ontology:text ?medication1 .
  ?medConcept2 fhir-ontology:text ?medication2 .

  # This would join with a drug interaction knowledge base
  # Simplified example showing structure
}
ORDER BY ?patientMRN ?interactionSeverity DESC
