import Foundation import SwiftUI import Combine @MainActor final class DashboardViewModel: ViewModel { @Published private(set) var patient: PatientDTO? @Published private(set) var prescriptions: [PrescriptionWithSchedulesResponse] = [] @Published private(set) var medications: [String: MedicationDTO] = [:] @Published private(set) var errorMessage: String? @Published private(set) var logoutErrorMessage: String? private let api: MedMapAPI = DIContainer.shared.resolve() var patientAge: Int? { guard let dateOfBirth = patient?.dateOfBirth else { return nil } let formatter = DateFormatter() formatter.locale = Locale(identifier: "en_US_POSIX") formatter.dateFormat = "yyyy-MM-dd" guard let birthDate = formatter.date(from: dateOfBirth) else { return nil } return Calendar.current.dateComponents([.year], from: birthDate, to: .now).year } var totalDosesToday: Int { medicationCards.reduce(0) { $0 + $1.doseTimes.count } } var medicationCards: [MedicationCard] { prescriptions.map { response in let times = response.schedules .flatMap(\.timesOfDay) .sorted() let medication = medications[response.medicationId] return MedicationCard( id: response.prescription.id, medicationId: response.medicationId, name: medication?.name ?? "Medicacao prescrita", tag: medication?.activeIngredient ?? medication?.dosageForm ?? "Ativo", photoBase64: medication?.medicationPhoto, doseTimes: times, nextDoseTime: times.first(where: { $0 >= currentTime }) ?? times.first ) } } func loadDashboard() async { guard !isLoading else { return } isLoading = true errorMessage = nil defer { isLoading = false } do { async let myPatient = api.getMyPatientProfile() async let activePrescriptions = api.listMyActivePrescriptions() async let medicationsResponse = api.listMedications() let (patient, prescriptions, medicationsResponseValue) = try await (myPatient, activePrescriptions, medicationsResponse) self.patient = patient self.prescriptions = prescriptions medications = Dictionary( uniqueKeysWithValues: medicationsResponseValue.medications.map { ($0.medicationId, $0) } ) } catch { errorMessage = "Nao foi possivel carregar a sua medicacao." fluxlog("Patient dashboard load failed: \(error.localizedDescription)") } } func logout() async { guard !isLoading else { return } isLoading = true logoutErrorMessage = nil defer { isLoading = false } do { try await api.logout() appStateManager.resetNavigation() appStateManager.navigateTo(state: .login) } catch { logoutErrorMessage = "Nao foi possivel terminar a sessao. Tente novamente." fluxlog("Patient logout failed: \(error.localizedDescription)") } } private var currentTime: String { let formatter = DateFormatter() formatter.locale = Locale(identifier: "en_US_POSIX") formatter.dateFormat = "HH:mm" return formatter.string(from: .now) } } struct MedicationCard: Identifiable { let id: String let medicationId: String let name: String let tag: String let photoBase64: String? let doseTimes: [String] let nextDoseTime: String? } // Created by RSA on 28/08/2026. //