import Foundation @MainActor protocol LeadDetailRemoteService { func fetchDetail(id: String, salesCode: String) async throws -> LeadDetailDTO func download(_ reference: LeadFileReference, leadID: String, salesCode: String) async throws -> Data } /// Transport boundary. A future HTTP adapter maps its response into this payload. struct LeadDetailDTO { let detail: LeadDetail func toDomain(expectedID: String) throws -> LeadDetail { let documents = detail.offers.flatMap(\.documents) let groups = detail.offers.flatMap(\.groups) guard detail.lead.id == expectedID, Set(detail.offers.map(\.id)).count == detail.offers.count, Set(groups.map(\.id)).count == groups.count, Set(documents.map(\.id)).count == documents.count, Set(detail.photos.map(\.id)).count == detail.photos.count, Set(detail.tankOptions.map(\.id)).count == detail.tankOptions.count, detail.offers.allSatisfy({ !$0.id.isEmpty && !$0.title.isEmpty && $0.amount >= 0 }), documents.allSatisfy({ !$0.id.isEmpty && !$0.title.isEmpty && $0.pageCount > 0 && $0.file.kind == .pdf && !$0.file.id.isEmpty && !$0.file.version.isEmpty }), detail.photos.allSatisfy({ $0.thumbnail.kind == .image && $0.original.kind == .image }) else { throw LeadError.invalidResponse } return detail } }