import Foundation // Mirrors Kotlin BmlContactsClient exactly. // Endpoint: GET /api/mobile/contacts // Response: { success: true, payload: [ { id, name, alias, account, status, currency }, ... ] } final class BmlContactsClient { private let base = "https://www.bankofmaldives.com.mv/internetbanking" private let ua = "bml-mobile-banking/348 (Apple; iOS 17.0; iPhone)" private let ver = "2.1.44.348" private let bmlSession: BmlSession private let urlSession: URLSession init(bmlSession: BmlSession) { self.bmlSession = bmlSession let cfg = URLSessionConfiguration.ephemeral cfg.timeoutIntervalForRequest = 30 self.urlSession = URLSession(configuration: cfg) } func fetchContacts(loginTag: String) async throws -> [BankContact] { var req = URLRequest(url: URL(string: "\(base)/api/mobile/contacts")!) req.setValue("Bearer \(bmlSession.accessToken)", forHTTPHeaderField: "Authorization") req.setValue(ua, forHTTPHeaderField: "User-Agent") req.setValue(ver, forHTTPHeaderField: "x-app-version") let (data, response) = try await urlSession.data(for: req) let code = (response as? HTTPURLResponse)?.statusCode ?? 0 if code == 401 || code == 419 { throw BmlError.sessionExpired } if code >= 500 { throw BmlError.networkError("HTTP \(code)") } guard let root = try? JSONSerialization.jsonObject(with: data) as? [String: Any], root["success"] as? Bool == true, let payload = root["payload"] as? [[String: Any]] else { return [] } return payload.compactMap { item -> BankContact? in let account = item["account"] as? String ?? "" guard !account.isEmpty else { return nil } let id = item["id"] as? Int ?? 0 let name = item["name"] as? String ?? "" let alias = (item["alias"] as? String).flatMap { $0.isEmpty ? nil : $0 } ?? name let status = item["status"] as? String ?? "S" let currency = item["currency"] as? String ?? "MVR" return BankContact( id: "BML_bml_\(id)_\(loginTag)", benefNo: "bml_\(id)", benefName: name, benefNickName: alias == name ? nil : alias, benefAccount: account, benefType: "I", bankColor: "#0066A1", benefBankName: "Bank of Maldives", bankCode: "", benefStatus: status, transferCyDesc: currency, customerImgHash: nil, benefCategoryId: "BML", profileId: loginTag, source: "BML" ) } } }