import Foundation /// A `Sendable` snapshot of one copy for sale, with the shop selling it. public struct Listing: Sendable, Equatable { // MARK: Properties /// The listing's URL slug. public let slug: String /// The shop selling the copy. public let shop: Shop /// The listing's title, e.g. `Nightward #1`. public let title: String /// The series the copy belongs to, e.g. `Nightward (2019 series)`. public let seriesTitle: String /// The issue or volume, e.g. `#1, cover A`. public let issueLabel: String /// The publisher's name. public let publisher: String /// The cover year. public let year: Int /// The format token, e.g. `single-issues`. public let format: String /// The printing in a few words, e.g. `1st print`. public let printing: String /// The printing in full, e.g. `First printing, direct edition`. public let printingDetail: String /// Whether the copy is a first printing. public let isFirstPrint: Bool /// The company that graded and slabbed the copy, or `nil` for a raw copy. public let grader: String? /// The numeric grade, or `nil` for formats that are not graded. public let grade: Double? /// The condition as the seller states it, e.g. `NM` or `Like new`. public let condition: String /// The grader's certificate number, or `nil` for a raw copy. public let certNumber: String? /// The page quality, or `nil` when not stated. public let pageQuality: String? /// Why the issue is a key, or `nil` when it is not one. public let keyNotes: String? /// The seller's notes on the copy. public let sellerNotes: String /// The asking price, in euro cents. public let priceCents: Int /// The shipping cost to the Netherlands, in euro cents. public let shippingCents: Int /// Whether the seller takes offers on the copy. public let acceptsOffers: Bool /// The placeholder cover shown until listings carry photos. public let cover: Cover /// When the copy was listed. public let listedAt: Date // MARK: Initializers public init( slug: String, shop: Shop, title: String, seriesTitle: String, issueLabel: String, publisher: String, year: Int, format: String, printing: String, printingDetail: String, isFirstPrint: Bool, grader: String?, grade: Double?, condition: String, certNumber: String?, pageQuality: String?, keyNotes: String?, sellerNotes: String, priceCents: Int, shippingCents: Int, acceptsOffers: Bool, cover: Cover, listedAt: Date ) { self.slug = slug self.shop = shop self.title = title self.seriesTitle = seriesTitle self.issueLabel = issueLabel self.publisher = publisher self.year = year self.format = format self.printing = printing self.printingDetail = printingDetail self.isFirstPrint = isFirstPrint self.grader = grader self.grade = grade self.condition = condition self.certNumber = certNumber self.pageQuality = pageQuality self.keyNotes = keyNotes self.sellerNotes = sellerNotes self.priceCents = priceCents self.shippingCents = shippingCents self.acceptsOffers = acceptsOffers self.cover = cover self.listedAt = listedAt } } // MARK: - Extensions public extension Listing { // MARK: Computed /// Whether the issue is a key. var isKey: Bool { keyNotes != nil } /// Whether the copy is graded and slabbed by a grading company. var isSlabbed: Bool { grader != nil } } // MARK: - Structs public extension Listing { /// A placeholder cover: lettering on a toned ground. struct Cover: Sendable, Equatable { // MARK: Properties /// The tone token naming the cover's colours, e.g. `navy`. public let tone: String /// The title lettering, one line per newline. public let title: String /// The publisher's imprint line. public let imprint: String /// The issue number or volume marker. public let number: String // MARK: Initializers public init( tone: String, title: String, imprint: String, number: String ) { self.tone = tone self.title = title self.imprint = imprint self.number = number } } }