AssessmentService.java
package com.medilabo.solutions.assessment.service;
import java.time.LocalDate;
import java.time.Period;
import java.util.List;
import org.springframework.stereotype.Service;
import com.medilabo.solutions.assessment.client.NoteServiceClient;
import com.medilabo.solutions.assessment.client.PatientServiceClient;
import com.medilabo.solutions.assessment.dto.DiabetesRiskLevelEnum;
import com.medilabo.solutions.assessment.dto.NoteDto;
import com.medilabo.solutions.assessment.dto.PatientDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RequiredArgsConstructor
@Service
public class AssessmentService {
private final PatientServiceClient patientServiceClient;
private final NoteServiceClient noteServiceClient;
private static final List<String> TRIGGER_TERMS = List.of(
"hémoglobine a1c",
"microalbumine",
"taille",
"poids",
"fumeur",
"fumeuse",
"anormal",
"cholestérol",
"vertige",
"rechute",
"réaction",
"anticorps");
/**
* Assesses the diabetes risk level for a given patient based on their age,
* gender, and medical notes.
*
* This method retrieves patient information and medical notes, then calculates
* the diabetes risk
* by analyzing trigger terms in the notes and applying risk assessment rules
* based on age and gender.
*
* @param patId the unique identifier of the patient to assess
* @return the calculated diabetes risk level as a DiabetesRiskLevelEnum
* @throws RuntimeException if patient data cannot be retrieved or if the
* patient ID is invalid
*
* @see DiabetesRiskLevelEnum
* @see PatientDto
* @see NoteDto
*/
public DiabetesRiskLevelEnum assessDiabetesRisk(int patId) {
log.info("Creating assessment for patient ID: {}", patId);
PatientDto patientDto = patientServiceClient.getPatientById(patId);
List<NoteDto> notes = noteServiceClient.getNoteByPatientId(patId);
int age = calculateAge(patientDto.getBirthDate());
boolean isMale = "M".equals(patientDto.getGender());
List<String> noteTexts = notes.stream().map(NoteDto::getNote).toList();
int triggerCount = countTriggerTerms(noteTexts);
DiabetesRiskLevelEnum riskLevel = calculateRiskLevel(age, isMale, triggerCount);
log.info("Assessment completed - Patient ID: {}, Age: {}, Gender: {}, Triggers: {}, Risk: {}",
patId, age, patientDto.getGender(), triggerCount, riskLevel);
return riskLevel;
}
private int calculateAge(LocalDate birthDate) {
return Period.between(birthDate, LocalDate.now()).getYears();
}
/**
* Counts the number of distinct trigger terms found in the provided list of
* notes.
*
* This method performs a case-insensitive search through all notes to identify
* trigger terms that are present. Each trigger term is counted only once,
* regardless of how many times it appears across all notes.
*
* @param notes the list of note strings to search through for trigger terms
* @return the count of distinct trigger terms found in the notes
*/
private int countTriggerTerms(List<String> notes) {
return (int) notes.stream()
.flatMap(note -> TRIGGER_TERMS.stream()
.filter(term -> note.toLowerCase().contains(term.toLowerCase())))
.distinct()
.count();
}
/**
* Calculates the diabetes risk level based on patient demographics and trigger
* count.
*
* The risk assessment follows different criteria based on age and gender:
* - For patients over 30: Risk is determined solely by trigger count
* - For patients 30 or under: Risk is determined by trigger count with
* different thresholds for males and females
*
* Risk levels are determined as follows:
* - NONE: No triggers present, or trigger count doesn't meet minimum thresholds
* - BORDERLINE: Only applies to patients over 30 with 2-5 triggers
* - IN_DANGER:
* - Patients over 30: 6-7 triggers
* - Males 30 or under: 3-4 triggers
* - Females 30 or under: 4-6 triggers
* - EARLY_ONSET:
* - Patients over 30: 8 or more triggers
* - Males 30 or under: 5 or more triggers
* - Females 30 or under: 7 or more triggers
*
* @param age the patient's age in years
* @param isMale true if the patient is male, false if female
* @param triggerCount the number of diabetes risk factor triggers identified
* @return the calculated diabetes risk level as a DiabetesRiskLevelEnum
*/
private DiabetesRiskLevelEnum calculateRiskLevel(int age, boolean isMale, int triggerCount) {
if (triggerCount == 0) {
return DiabetesRiskLevelEnum.NONE;
}
if (age > 30) {
if (triggerCount >= 2 && triggerCount <= 5) {
return DiabetesRiskLevelEnum.BORDERLINE;
} else if (triggerCount >= 6 && triggerCount <= 7) {
return DiabetesRiskLevelEnum.IN_DANGER;
} else if (triggerCount >= 8) {
return DiabetesRiskLevelEnum.EARLY_ONSET;
}
} else {
if (isMale) {
if (triggerCount >= 3 && triggerCount <= 4) {
return DiabetesRiskLevelEnum.IN_DANGER;
} else if (triggerCount >= 5) {
return DiabetesRiskLevelEnum.EARLY_ONSET;
}
} else {
if (triggerCount >= 4 && triggerCount <= 6) {
return DiabetesRiskLevelEnum.IN_DANGER;
} else if (triggerCount >= 7) {
return DiabetesRiskLevelEnum.EARLY_ONSET;
}
}
}
return DiabetesRiskLevelEnum.NONE;
}
}