1→import Foundation 2→import SwiftUI 3→ 4→// MARK: - Budget Category 5→struct BudgetCategory: Identifiable, Codable { 6→ let id: UUID 7→ var category: ExpenseCategory 8→ var limit: Double 9→ var spent: Double 10→ var isActive: Bool 11→ 12→ init( 13→ id: UUID = UUID(), 14→ category: ExpenseCategory, 15→ limit: Double, 16→ spent: Double = 0, 17→ isActive: Bool = true 18→ ) { 19→ self.id = id 20→ self.category = category 21→ self.limit = limit 22→ self.spent = spent 23→ self.isActive = isActive 24→ } 25→ 26→ var remaining: Double { 27→ max(0, limit - spent) 28→ } 29→ 30→ var progress: Double { 31→ guard limit > 0 else { return 0 } 32→ return min(spent / limit, 1.5) 33→ } 34→ 35→ var progressPercentage: String { 36→ String(format: "%.0f%%", min(progress * 100, 999)) 37→ } 38→ 39→ var isOverBudget: Bool { 40→ spent > limit 41→ } 42→ 43→ var overAmount: Double { 44→ max(0, spent - limit) 45→ } 46→ 47→ var status: BudgetStatus { 48→ let ratio = spent / limit 49→ switch ratio { 50→ case 0..<0.5: return .safe 51→ case 0.5..<0.75: return .caution 52→ case 0.75..<1.0: return .warning 53→ default: return .exceeded 54→ } 55→ } 56→} 57→ 58→// MARK: - Budget Status 59→enum BudgetStatus: String { 60→ case safe = "Tranquilo" 61→ case caution = "Atencao" 62→ case warning = "Cuidado" 63→ case exceeded = "Estourado" 64→ 65→ var color: Color { 66→ switch self { 67→ case .safe: return .green 68→ case .caution: return .yellow 69→ case .warning: return .orange 70→ case .exceeded: return .red 71→ } 72→ } 73→ 74→ var icon: String { 75→ switch self { 76→ case .safe: return "checkmark.circle.fill" 77→ case .caution: return "exclamationmark.circle.fill" 78→ case .warning: return "exclamationmark.triangle.fill" 79→ case .exceeded: return "xmark.circle.fill" 80→ } 81→ } 82→} 83→ 84→// MARK: - Monthly Budget 85→struct MonthlyBudget: Identifiable, Codable { 86→ let id: UUID 87→ var month: Date 88→ var categories: [BudgetCategory] 89→ var notes: String 90→ 91→ init( 92→ id: UUID = UUID(), 93→ month: Date = Date(), 94→ categories: [BudgetCategory] = [], 95→ notes: String = "" 96→ ) { 97→ self.id = id 98→ self.month = month 99→ self.categories = categories 100→ self.notes = notes 101→ } 102→ 103→ var totalLimit: Double { 104→ categories.filter { $0.isActive }.reduce(0) { $0 + $1.limit } 105→ } 106→ 107→ var totalSpent: Double { 108→ categories.filter { $0.isActive }.reduce(0) { $0 + $1.spent } 109→ } 110→ 111→ var totalRemaining: Double { 112→ max(0, totalLimit - totalSpent) 113→ } 114→ 115→ var overallProgress: Double { 116→ guard totalLimit > 0 else { return 0 } 117→ return totalSpent / totalLimit 118→ } 119→ 120→ var categoriesOverBudget: Int { 121→ categories.filter { $0.isOverBudget && $0.isActive }.count 122→ } 123→ 124→ var monthName: String { 125→ let formatter = DateFormatter() 126→ formatter.dateFormat = "MMMM yyyy" 127→ formatter.locale = Locale(identifier: "pt_BR") 128→ return formatter.string(from: month).capitalized 129→ } 130→} 131→ 132→// MARK: - Budget Manager 133→@MainActor 134→class BudgetManager: ObservableObject { 135→ static let shared = BudgetManager() 136→ 137→ @Published var currentBudget: MonthlyBudget 138→ @Published var budgetHistory: [MonthlyBudget] = [] 139→ 140→ private let storageKey = "neog_finance_budget" 141→ private let historyKey = "neog_finance_budget_history" 142→ 143→ private init() { 144→ currentBudget = MonthlyBudget() 145→ loadData() 146→ if currentBudget.categories.isEmpty { 147→ setupDefaultBudget() 148→ } 149→ updateSpentFromTransactions() 150→ } 151→ 152→ // MARK: - Computed Properties 153→ 154→ var activeCategories: [BudgetCategory] { 155→ currentBudget.categories.filter { $0.isActive } 156→ .sorted { $0.progress > $1.progress } 157→ } 158→ 159→ var categoriesNeedingAttention: [BudgetCategory] { 160→ activeCategories.filter { $0.status == .warning || $0.status == .exceeded } 161→ } 162→ 163→ var healthScore: Int { 164→ let active = activeCategories 165→ guard !active.isEmpty else { return 100 } 166→ 167→ let scores = active.map { category -> Int in 168→ switch category.status { 169→ case .safe: return 100 170→ case .caution: return 75 171→ case .warning: return 50 172→ case .exceeded: return 0 173→ } 174→ } 175→ 176→ return scores.reduce(0, +) / scores.count 177→ } 178→ 179→ var healthStatus: String { 180→ switch healthScore { 181→ case 80...100: return "Excelente" 182→ case 60..<80: return "Bom" 183→ case 40..<60: return "Regular" 184→ case 20..<40: return "Ruim" 185→ default: return "Critico" 186→ } 187→ } 188→ 189→ var healthColor: Color { 190→ switch healthScore { 191→ case 80...100: return .green 192→ case 60..<80: return .blue 193→ case 40..<60: return .yellow 194→ case 20..<40: return .orange 195→ default: return .red 196→ } 197→ } 198→ 199→ // MARK: - Budget Operations 200→ 201→ func updateCategoryLimit(categoryId: UUID, newLimit: Double) { 202→ if let index = currentBudget.categories.firstIndex(where: { $0.id == categoryId }) { 203→ currentBudget.categories[index].limit = newLimit 204→ saveData() 205→ } 206→ } 207→ 208→ func toggleCategory(categoryId: UUID) { 209→ if let index = currentBudget.categories.firstIndex(where: { $0.id == categoryId }) { 210→ currentBudget.categories[index].isActive.toggle() 211→ saveData() 212→ } 213→ } 214→ 215→ func addCategory(_ category: ExpenseCategory, limit: Double) { 216→ // Check if category already exists 217→ if currentBudget.categories.contains(where: { $0.category == category }) { 218→ return 219→ } 220→ 221→ let newCategory = BudgetCategory(category: category, limit: limit) 222→ currentBudget.categories.append(newCategory) 223→ saveData() 224→ } 225→ 226→ func removeCategory(categoryId: UUID) { 227→ currentBudget.categories.removeAll { $0.id == categoryId } 228→ saveData() 229→ } 230→ 231→ func updateSpentFromTransactions() { 232→ let dataManager = DataManager.shared 233→ let calendar = Calendar.current 234→ 235→ // Get current month transactions 236→ let currentMonthExpenses = dataManager.transactions.filter { transaction in 237→ transaction.type == .expense && 238→ calendar.isDate(transaction.date, equalTo: Date(), toGranularity: .month) 239→ } 240→ 241→ // Reset spent values 242→ for index in currentBudget.categories.indices { 243→ currentBudget.categories[index].spent = 0 244→ } 245→ 246→ // Calculate spent per category 247→ for expense in currentMonthExpenses { 248→ if let categoryEnum = ExpenseCategory(rawValue: expense.category), 249→ let index = currentBudget.categories.firstIndex(where: { $0.category == categoryEnum }) { 250→ currentBudget.categories[index].spent += expense.amount 251→ } 252→ } 253→ 254→ saveData() 255→ } 256→ 257→ func addExpense(category: ExpenseCategory, amount: Double) { 258→ if let index = currentBudget.categories.firstIndex(where: { $0.category == category }) { 259→ currentBudget.categories[index].spent += amount 260→ saveData() 261→ } 262→ } 263→ 264→ // MARK: - Month Management 265→ 266→ func startNewMonth() { 267→ // Archive current budget 268→ budgetHistory.append(currentBudget) 269→ 270→ // Create new budget with same limits but zero spent 271→ let newCategories = currentBudget.categories.map { category in 272→ BudgetCategory( 273→ category: category.category, 274→ limit: category.limit, 275→ spent: 0, 276→ isActive: category.isActive 277→ ) 278→ } 279→ 280→ currentBudget = MonthlyBudget(categories: newCategories) 281→ saveData() 282→ } 283→ 284→ func copyFromPreviousMonth() { 285→ guard let previous = budgetHistory.last else { return } 286→ 287→ let newCategories = previous.categories.map { category in 288→ BudgetCategory( 289→ category: category.category, 290→ limit: category.limit, 291→ spent: 0, 292→ isActive: category.isActive 293→ ) 294→ } 295→ 296→ currentBudget.categories = newCategories 297→ saveData() 298→ } 299→ 300→ // MARK: - Persistence 301→ 302→ private func saveData() { 303→ if let encoded = try? JSONEncoder().encode(currentBudget) { 304→ UserDefaults.standard.set(encoded, forKey: storageKey) 305→ } 306→ if let encoded = try? JSONEncoder().encode(budgetHistory) { 307→ UserDefaults.standard.set(encoded, forKey: historyKey) 308→ } 309→ } 310→ 311→ private func loadData() { 312→ if let data = UserDefaults.standard.data(forKey: storageKey), 313→ let decoded = try? JSONDecoder().decode(MonthlyBudget.self, from: data) { 314→ currentBudget = decoded 315→ } 316→ if let data = UserDefaults.standard.data(forKey: historyKey), 317→ let decoded = try? JSONDecoder().decode([MonthlyBudget].self, from: data) { 318→ budgetHistory = decoded 319→ } 320→ } 321→ 322→ // MARK: - Default Budget Setup 323→ private func setupDefaultBudget() { 324→ let dataManager = DataManager.shared 325→ 326→ // Create budget based on recurring expenses 327→ var categories: [BudgetCategory] = [] 328→ 329→ // Housing (aluguel) 330→ categories.append(BudgetCategory(category: .housing, limit: 4000)) 331→ 332→ // Food (marmitas) 333→ categories.append(BudgetCategory(category: .food, limit: 3500)) 334→ 335→ // Family 336→ categories.append(BudgetCategory(category: .family, limit: 3000)) 337→ 338→ // Utilities 339→ categories.append(BudgetCategory(category: .utilities, limit: 400)) 340→ 341→ // Software/IA 342→ categories.append(BudgetCategory(category: .software, limit: 500)) 343→ 344→ // Entertainment 345→ categories.append(BudgetCategory(category: .entertainment, limit: 500)) 346→ 347→ // Health 348→ categories.append(BudgetCategory(category: .health, limit: 300)) 349→ 350→ // Transportation 351→ categories.append(BudgetCategory(category: .transportation, limit: 400)) 352→ 353→ // Other 354→ categories.append(BudgetCategory(category: .other, limit: 1000)) 355→ 356→ currentBudget = MonthlyBudget(categories: categories) 357→ saveData() 358→ } 359→ 360→ func resetToDefault() { 361→ currentBudget = MonthlyBudget() 362→ setupDefaultBudget() 363→ updateSpentFromTransactions() 364→ } 365→} 366→ Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.