import Foundation import CoreData import Combine class AccountRepository: ObservableObject { private let context: NSManagedObjectContext @Published private(set) var accounts: [Account] = [] init(context: NSManagedObjectContext = CoreDataStack.shared.viewContext) { self.context = context fetchAccounts() setupNotificationObserver() } private func setupNotificationObserver() { NotificationCenter.default.addObserver( self, selector: #selector(contextDidChange), name: .NSManagedObjectContextObjectsDidChange, object: context ) } @objc private func contextDidChange(_ notification: Notification) { fetchAccounts() } // MARK: - Fetch func fetchAccounts() { context.perform { [weak self] in guard let self else { return } let request: NSFetchRequest = Account.fetchRequest() request.sortDescriptors = [ NSSortDescriptor(keyPath: \Account.sortOrder, ascending: true), NSSortDescriptor(keyPath: \Account.createdAt, ascending: true) ] do { let fetched = try self.context.fetch(request) DispatchQueue.main.async { self.accounts = fetched } } catch { print("Failed to fetch accounts: \(error)") DispatchQueue.main.async { self.accounts = [] } } } } func fetchAccount(by id: UUID) -> Account? { let request: NSFetchRequest = Account.fetchRequest() request.predicate = NSPredicate(format: "id == %@", id as CVarArg) request.fetchLimit = 1 return try? context.fetch(request).first } // MARK: - Create @discardableResult func createAccount( name: String, currency: String?, inputMode: InputMode, notificationFrequency: NotificationFrequency, customFrequencyMonths: Int = 1 ) -> Account { let account = Account(context: context) account.name = name account.currency = currency account.inputMode = inputMode.rawValue account.notificationFrequency = notificationFrequency.rawValue account.customFrequencyMonths = Int16(customFrequencyMonths) account.sortOrder = Int16(accounts.count) save() return account } func createDefaultAccountIfNeeded() -> Account { if let existing = accounts.first { return existing } let defaultCurrency = AppSettings.getOrCreate(in: context).currency let account = createAccount( name: "Personal", currency: defaultCurrency, inputMode: .simple, notificationFrequency: .monthly ) // Attach existing sources to the default account let request: NSFetchRequest = InvestmentSource.fetchRequest() if let sources = try? context.fetch(request) { for source in sources where source.account == nil { source.account = account } save() } return account } // MARK: - Update func updateAccount( _ account: Account, name: String? = nil, currency: String? = nil, inputMode: InputMode? = nil, notificationFrequency: NotificationFrequency? = nil, customFrequencyMonths: Int? = nil ) { if let name = name { account.name = name } if let currency = currency { account.currency = currency } if let inputMode = inputMode { account.inputMode = inputMode.rawValue } if let notificationFrequency = notificationFrequency { account.notificationFrequency = notificationFrequency.rawValue } if let customMonths = customFrequencyMonths { account.customFrequencyMonths = Int16(customMonths) } save() } // MARK: - Delete func deleteAccount(_ account: Account) { context.delete(account) save() } // MARK: - Save private func save() { guard context.hasChanges else { return } do { try context.save() fetchAccounts() } catch { print("Failed to save accounts: \(error)") } } }