import Foundation // MARK: - Unified bank data models // These aggregate MIB, BML, and Fahipay responses into a common schema. // All types are Codable for cache serialisation and Hashable for use in SwiftUI ForEach. struct BankAccount: Identifiable, Codable, Hashable { let id: String // Synthetic: "\(bank)_\(accountNumber)_\(loginTag)" let bank: String // "MIB" | "BML" | "FAHIPAY" let profileName: String let profileType: String let productCode: String let accountNumber: String let accountBriefName: String let currencyName: String // "MVR" | "USD" | ... let accountTypeName: String let availableBalance: Double let currentBalance: Double let blockedAmount: Double let mvrBalance: Double? // Converted balance when currency != MVR let statusDesc: String let profileImageHash: String? let loginTag: String // loginId that owns this account let profileId: String? let internalId: String? var isActive: Bool { statusDesc.lowercased().contains("active") } var formattedAvailableBalance: String { "\(currencyName) \(Self.balanceFormatter.string(from: NSNumber(value: availableBalance)) ?? "0.00")" } private static let balanceFormatter: NumberFormatter = { let f = NumberFormatter() f.numberStyle = .decimal f.minimumFractionDigits = 2 f.maximumFractionDigits = 2 return f }() } struct BankContact: Identifiable, Codable, Hashable { let id: String // Unique composite across banks let benefNo: String let benefName: String let benefNickName: String? let benefAccount: String let benefType: String // "MIB" | "LOCAL" | "SWIFT" | "BML" | "FAHIPAY" let bankColor: String? let benefBankName: String? let bankCode: String? let benefStatus: String let transferCyDesc: String? let customerImgHash: String? let benefCategoryId: String? let profileId: String? let source: String // "MIB" | "BML" | "FAHIPAY" var displayName: String { if let nick = benefNickName, !nick.isEmpty { return nick } return benefName } } struct BankTransaction: Identifiable, Codable, Hashable { let id: String let date: Date let description: String let amount: Double // Positive = credit, negative = debit let currency: String let counterpartyName: String? let reference: String? let accountNumber: String let accountDisplayName: String let source: String // "MIB" | "BML" | "BML_CARD" | "FAHIPAY" let iconUrl: String? var isCredit: Bool { amount >= 0 } var formattedAmount: String { let sign = isCredit ? "+" : "-" let abs = Self.amountFormatter.string(from: NSNumber(value: Swift.abs(amount))) ?? "0.00" return "\(sign) \(currency) \(abs)" } private static let amountFormatter: NumberFormatter = { let f = NumberFormatter() f.numberStyle = .decimal f.minimumFractionDigits = 2 f.maximumFractionDigits = 2 return f }() } struct BankContactCategory: Identifiable, Codable, Hashable { let id: String let categoryName: String let numBenef: Int let source: String // "MIB" | "FAHIPAY" } struct BankNotification: Identifiable, Codable, Hashable { let id: String let title: String let body: String let date: Date var isRead: Bool let source: String } // MARK: - Transfer struct TransferResult: Codable { let success: Bool let transactionId: String? let reference: String? let date: Date? let errorMessage: String? } struct TransferReceiptData: Sendable, Equatable { let fromAccountNumber: String let fromBankName: String let toAccountNumber: String let toAccountName: String let amount: Double let currency: String let reference: String let date: String let message: String } struct RecentPick: Identifiable, Codable, Hashable { let id: String let benefName: String let benefAccount: String let transferNetwork: String // TransferNetwork.rawValue let bankName: String? let lastUsed: Date } // MARK: - Connectivity enum ConnectivityError: String, CaseIterable, Codable { case noInternet = "NO_INTERNET" case mib = "MIB" case bml = "BML" case fahipay = "FAHIPAY" }