import Foundation import SwiftUI // MARK: - Race struct Race: Identifiable, Equatable, Codable { let id: String let name: String let description: String let location: String let latitude: Double let longitude: Double let raceDate: Date let distanceKm: Double let raceType: RaceType let organizerName: String let registrationUrl: String? let imageUrl: String? let participantCount: Int? let isRegistered: Bool let isSaved: Bool let elevationGain: Double let terrainType: TerrainType enum CodingKeys: String, CodingKey { case id, name, description, location, latitude, longitude, raceDate, distanceKm, raceType, organizerName, registrationUrl, imageUrl, participantCount, isRegistered, isSaved, elevationGain, terrainType } init( id: String, name: String, description: String, location: String, latitude: Double, longitude: Double, raceDate: Date, distanceKm: Double, raceType: RaceType, organizerName: String, registrationUrl: String?, imageUrl: String?, participantCount: Int?, isRegistered: Bool, isSaved: Bool, elevationGain: Double, terrainType: TerrainType ) { self.id = id self.name = name self.description = description self.location = location self.latitude = latitude self.longitude = longitude self.raceDate = raceDate self.distanceKm = distanceKm self.raceType = raceType self.organizerName = organizerName self.registrationUrl = registrationUrl self.imageUrl = imageUrl self.participantCount = participantCount self.isRegistered = isRegistered self.isSaved = isSaved self.elevationGain = elevationGain self.terrainType = terrainType } static func == (lhs: Race, rhs: Race) -> Bool { lhs.id == rhs.id && lhs.isRegistered == rhs.isRegistered && lhs.isSaved == rhs.isSaved } var daysUntilRace: Int { let calendar = Calendar.current return calendar.dateComponents([.day], from: Date(), to: raceDate).day ?? 0 } var isUpcoming: Bool { raceDate > Date() } } // MARK: - Race Type enum RaceType: String, CaseIterable, Codable { case road case trail case track case virtual var displayName: String { switch self { case .road: return "Road" case .trail: return "Trail" case .track: return "Track" case .virtual: return "Virtual" } } var icon: String { switch self { case .road: return "car.fill" case .trail: return "mountain.2.fill" case .track: return "circle.fill" case .virtual: return "globe" } } } // MARK: - Terrain Type enum TerrainType: String, CaseIterable, Codable { case flat case rolling case hilly case mountainous var displayName: String { switch self { case .flat: return "Flat" case .rolling: return "Rolling" case .hilly: return "Hilly" case .mountainous: return "Mountainous" } } } // MARK: - Race Filter struct RaceFilter: Encodable { var distanceKm: Double? var raceType: RaceType? var terrainType: TerrainType? var startDate: Date? var endDate: Date? var location: String? var radiusKm: Double? var limit: Int var offset: Int init( distanceKm: Double? = nil, raceType: RaceType? = nil, terrainType: TerrainType? = nil, startDate: Date? = nil, endDate: Date? = nil, location: String? = nil, radiusKm: Double? = nil, limit: Int = 20, offset: Int = 0 ) { self.distanceKm = distanceKm self.raceType = raceType self.terrainType = terrainType self.startDate = startDate self.endDate = endDate self.location = location self.radiusKm = radiusKm self.limit = limit self.offset = offset } } // MARK: - API Response Types struct RaceListResponse: Decodable { let races: [Race] let hasMore: Bool } struct RaceDetailResponse: Decodable { let race: Race } struct SaveRaceResponse: Decodable { let success: Bool let raceId: String let isSaved: Bool } struct RegisterRaceResponse: Decodable { let success: Bool let raceId: String let registrationUrl: String? }