TDDSetup.swift 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import CoreData
  2. import Foundation
  3. extension Stat.StateModel {
  4. func setupTDDs() {
  5. Task {
  6. let tddStats = await fetchAndMapDeterminations()
  7. await MainActor.run {
  8. self.tddStats = tddStats
  9. }
  10. }
  11. }
  12. func fetchAndMapDeterminations() async -> [TDD] {
  13. let results = await CoreDataStack.shared.fetchEntitiesAsync(
  14. ofType: OrefDetermination.self,
  15. onContext: determinationFetchContext,
  16. predicate: NSPredicate.determinationsForStats,
  17. key: "deliverAt",
  18. ascending: true,
  19. propertiesToFetch: ["objectID", "timestamp", "deliverAt", "totalDailyDose"]
  20. )
  21. return await determinationFetchContext.perform {
  22. guard let fetchedResults = results as? [[String: Any]] else { return [] }
  23. // Group determinations by day
  24. let calendar = Calendar.current
  25. let groupedByDay = Dictionary(grouping: fetchedResults) { result -> Date in
  26. guard let deliverAt = result["deliverAt"] as? Date else { return Date() }
  27. return calendar.startOfDay(for: deliverAt)
  28. }
  29. // Calculate total daily doses for each day
  30. return groupedByDay.map { date, determinations -> TDD in
  31. let totalDose = determinations.reduce(Decimal.zero) { sum, determination in
  32. sum + (determination["totalDailyDose"] as? Decimal ?? 0)
  33. }
  34. // Calculate average dose for the day
  35. let count = Decimal(determinations.count)
  36. let averageDose = count > 0 ? totalDose / count : 0
  37. return TDD(
  38. totalDailyDose: averageDose,
  39. timestamp: date
  40. )
  41. }
  42. }
  43. }
  44. var averageTDD: Decimal {
  45. let calendar = Calendar.current
  46. let now = Date()
  47. // Filter TDDs based on selected time frame
  48. let filteredTDDs: [TDD] = tddStats.filter { tdd in
  49. guard let timestamp = tdd.timestamp else { return false }
  50. switch selectedDurationForInsulinStats {
  51. case .Day:
  52. // Last 3 days
  53. let threeDaysAgo = calendar.date(byAdding: .day, value: -3, to: now)!
  54. return timestamp >= threeDaysAgo
  55. case .Week:
  56. // Last week
  57. let weekAgo = calendar.date(byAdding: .weekOfYear, value: -1, to: now)!
  58. return timestamp >= weekAgo
  59. case .Month:
  60. // Last month
  61. let monthAgo = calendar.date(byAdding: .month, value: -1, to: now)!
  62. return timestamp >= monthAgo
  63. case .Total:
  64. // Last 3 months
  65. let threeMonthsAgo = calendar.date(byAdding: .month, value: -3, to: now)!
  66. return timestamp >= threeMonthsAgo
  67. }
  68. }
  69. let sum = filteredTDDs.reduce(Decimal.zero) { $0 + ($1.totalDailyDose ?? 0) }
  70. return filteredTDDs.isEmpty ? 0 : sum / Decimal(filteredTDDs.count)
  71. }
  72. func calculateAverageTDD(from startDate: Date, to endDate: Date) async -> Decimal {
  73. let filteredTDDs = tddStats.filter { tdd in
  74. guard let timestamp = tdd.timestamp else { return false }
  75. return timestamp >= startDate && timestamp <= endDate
  76. }
  77. let sum = filteredTDDs.reduce(Decimal.zero) { $0 + ($1.totalDailyDose ?? 0) }
  78. return filteredTDDs.isEmpty ? 0 : sum / Decimal(filteredTDDs.count)
  79. }
  80. func calculateMedianTDD(from startDate: Date, to endDate: Date) async -> Decimal {
  81. let filteredTDDs = tddStats.filter { tdd in
  82. guard let timestamp = tdd.timestamp else { return false }
  83. return timestamp >= startDate && timestamp <= endDate
  84. }
  85. let sortedDoses = filteredTDDs.compactMap(\.totalDailyDose).sorted()
  86. guard !sortedDoses.isEmpty else { return 0 }
  87. let middle = sortedDoses.count / 2
  88. if sortedDoses.count % 2 == 0 {
  89. return (sortedDoses[middle - 1] + sortedDoses[middle]) / 2
  90. } else {
  91. return sortedDoses[middle]
  92. }
  93. }
  94. }