ContactSyncMapper.swift 50 lignes · 2498 octets
import Foundation

/// Maps a local contact entity to the server `ContactInput` JSON
/// (Kotlin `ContactSyncMapper`; conforms to the Data-layer port).
struct ContactSyncMapper: ContactSyncPayloadMapping {
    func toCreatePayload(_ entity: CrmContactEntity) -> String {
        SyncJson.encodeToString(Self.request(from: entity))
    }

    func toUpdatePayload(_ entity: CrmContactEntity) -> String {
        toCreatePayload(entity)
    }

    private static func request(from entity: CrmContactEntity) -> CreateContactRequest {
        let (prenom, nom) = resolveNames(entity)
        let entrepriseId = nonBlank(entity.entrepriseServerId)
        let company = entity.company?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
        return CreateContactRequest(
            prenom: prenom,
            nom: nom,
            entrepriseId: entrepriseId,
            // Scanned company name sent only without a server link: the server resolves or creates.
            entrepriseNom: (entrepriseId == nil && !company.isEmpty) ? company : nil,
            fonction: entity.jobTitle ?? "",
            emails: entity.emails.compactMap(nonBlank).map { ContactValeurDto(valeur: $0.trimmingCharacters(in: .whitespacesAndNewlines)) },
            telephones: entity.phones.compactMap(nonBlank).map { ContactValeurDto(valeur: $0.trimmingCharacters(in: .whitespacesAndNewlines)) },
            notes: entity.notes ?? "",
            statut: nonBlank(entity.statut) ?? "prospect",
            etape: nonBlank(entity.etape) ?? "nouveau",
            tags: entity.tags
        )
    }

    private static func nonBlank(_ value: String?) -> String? {
        guard let value, !value.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { return nil }
        return value
    }

    private static func resolveNames(_ entity: CrmContactEntity) -> (String, String) {
        let fn = entity.firstName?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
        let ln = entity.lastName?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
        if !fn.isEmpty || !ln.isEmpty { return (fn, ln) }
        let full = entity.fullName?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
        if full.isEmpty { return ("", "") }
        let parts = full.split(maxSplits: 1, whereSeparator: { $0.isWhitespace })
        if parts.count == 1 { return ("", String(parts[0])) }
        let rest = String(parts[1].drop(while: { $0.isWhitespace }))
        return (String(parts[0]), rest)
    }
}