import Foundation /// A real-world encounter between two present users. /// /// An encounter is deliberately **anonymous** until both parties mutually /// consent to reveal. Until then it is a "silhouette" — a proof that two /// humans were physically near each other, with no identity attached. struct Encounter: Identifiable, Codable, Hashable { let id: UUID let remoteAnonToken: String let timestamp: Date let tier: DistanceTier let engine: ProximityEngine /// Coarse geohash (optional). Never precise location. var geohash: String? /// The relationship state of this encounter. var status: EncounterStatus /// A human-readable hint, e.g. "Cafe on 5th Ave" if the user tagged it. var placeHint: String? init( id: UUID = UUID(), remoteAnonToken: String, timestamp: Date = Date(), tier: DistanceTier, engine: ProximityEngine, geohash: String? = nil, status: EncounterStatus = .silhouette, placeHint: String? = nil ) { self.id = id self.remoteAnonToken = remoteAnonToken self.timestamp = timestamp self.tier = tier self.engine = engine self.geohash = geohash self.status = status self.placeHint = placeHint } } /// Relationship lifecycle of an encounter. enum EncounterStatus: String, Codable, Hashable { /// Seen but not yet acknowledged. A silhouette. case silhouette /// This user has sent a "wave" (interest) but the other hasn't replied. case waved /// Both parties waved — identities revealed, chat unlocked. case mutual /// One party declined or blocked. Permanently removed from the graph. case declined }