import Foundation import CoreData import Combine class GoalRepository: ObservableObject { private let context: NSManagedObjectContext @Published private(set) var goals: [Goal] = [] init(context: NSManagedObjectContext = CoreDataStack.shared.viewContext) { self.context = context fetchGoals() setupNotificationObserver() } private func setupNotificationObserver() { NotificationCenter.default.addObserver( self, selector: #selector(contextDidChange), name: .NSManagedObjectContextObjectsDidChange, object: context ) } @objc private func contextDidChange(_ notification: Notification) { fetchGoals() } // MARK: - Fetch func fetchGoals(for account: Account? = nil) { context.perform { [weak self] in guard let self else { return } let request: NSFetchRequest = Goal.fetchRequest() if let account = account { request.predicate = NSPredicate(format: "account == %@", account) } request.sortDescriptors = [ NSSortDescriptor(keyPath: \Goal.createdAt, ascending: true) ] do { let fetched = try self.context.fetch(request) DispatchQueue.main.async { self.goals = fetched } } catch { print("Failed to fetch goals: \(error)") DispatchQueue.main.async { self.goals = [] } } } } // MARK: - Create @discardableResult func createGoal( name: String, targetAmount: Decimal, targetDate: Date? = nil, account: Account? ) -> Goal { let goal = Goal(context: context) goal.name = name goal.targetAmount = NSDecimalNumber(decimal: targetAmount) goal.targetDate = targetDate goal.account = account save() return goal } // MARK: - Update func updateGoal( _ goal: Goal, name: String? = nil, targetAmount: Decimal? = nil, targetDate: Date? = nil, clearTargetDate: Bool = false, isActive: Bool? = nil ) { if let name = name { goal.name = name } if let targetAmount = targetAmount { goal.targetAmount = NSDecimalNumber(decimal: targetAmount) } if clearTargetDate { goal.targetDate = nil } else if let targetDate = targetDate { goal.targetDate = targetDate } if let isActive = isActive { goal.isActive = isActive } save() } func deleteGoal(_ goal: Goal) { context.delete(goal) save() } // MARK: - Save private func save() { guard context.hasChanges else { return } do { try context.save() fetchGoals() } catch { print("Failed to save goals: \(error)") } } }