import Foundation import SwiftUI // MARK: - Challenge struct Challenge: Identifiable, Equatable, Codable { let id: String let title: String let description: String let challengeType: ChallengeType var status: ChallengeStatus let startDate: Date let endDate: Date let targetMetric: ChallengeMetric let targetValue: Double let targetUnit: String var participantCount: Int let rules: String? let imageUrl: String? let createdBy: String let createdByName: String let clubId: String? var participationStatus: ParticipationStatus var userProgress: Double? let createdAt: Date enum CodingKeys: String, CodingKey { case id, title, description, challengeType, status, startDate, endDate, targetMetric, targetValue, targetUnit, participantCount, rules, imageUrl, createdBy, createdByName, clubId, participationStatus, userProgress, createdAt } init( id: String, title: String, description: String, challengeType: ChallengeType, status: ChallengeStatus, startDate: Date, endDate: Date, targetMetric: ChallengeMetric, targetValue: Double, targetUnit: String, participantCount: Int, rules: String?, imageUrl: String?, createdBy: String, createdByName: String, clubId: String?, participationStatus: ParticipationStatus, userProgress: Double?, createdAt: Date ) { self.id = id self.title = title self.description = description self.challengeType = challengeType self.status = status self.startDate = startDate self.endDate = endDate self.targetMetric = targetMetric self.targetValue = targetValue self.targetUnit = targetUnit self.participantCount = participantCount self.rules = rules self.imageUrl = imageUrl self.createdBy = createdBy self.createdByName = createdByName self.clubId = clubId self.participationStatus = participationStatus self.userProgress = userProgress self.createdAt = createdAt } static func == (lhs: Challenge, rhs: Challenge) -> Bool { lhs.id == rhs.id && lhs.participationStatus == rhs.participationStatus } var progressPercentage: Double { guard let progress = userProgress else { return 0 } return min((progress / targetValue) * 100, 100) } var daysRemaining: Int { let calendar = Calendar.current let components = calendar.dateComponents([.day], from: Date(), to: endDate) return components.day ?? 0 } var isUpcoming: Bool { startDate > Date() } var isActive: Bool { Date() >= startDate && Date() <= endDate } var isCompleted: Bool { endDate < Date() } } // MARK: - Challenge Type enum ChallengeType: String, CaseIterable, Codable { case distance case time case frequency case elevation case calories case streak var displayName: String { switch self { case .distance: return "Distance" case .time: return "Time" case .frequency: return "Frequency" case .elevation: return "Elevation" case .calories: return "Calories" case .streak: return "Streak" } } var icon: String { switch self { case .distance: return "arrow.right.arrow.left" case .time: return "stopwatch.fill" case .frequency: return "repeat" case .elevation: return "mountain.2.fill" case .calories: return "flame.fill" case .streak: return "calendar.badge.clock" } } var color: Color { switch self { case .distance: return .blue case .time: return .orange case .frequency: return .green case .elevation: return .brown case .calories: return .red case .streak: return .purple } } } // MARK: - Challenge Status enum ChallengeStatus: String, CaseIterable, Codable { case upcoming case active case completed case cancelled } // MARK: - Challenge Metric enum ChallengeMetric: String, CaseIterable, Codable { case distance case time case frequency case elevation case calories var unit: String { switch self { case .distance: return "km" case .time: return "min" case .frequency: return "sessions" case .elevation: return "m" case .calories: return "kcal" } } var displayName: String { switch self { case .distance: return "Distance" case .time: return "Time" case .frequency: return "Sessions" case .elevation: return "Elevation" case .calories: return "Calories" } } } // MARK: - Participation Status enum ParticipationStatus: String, CaseIterable, Codable { case participating case notParticipating case invited } // MARK: - Challenge Participant struct ChallengeParticipant: Identifiable, Codable { let id: String let name: String let avatarUrl: String? let progress: Double let rank: Int let joinedAt: Date } // MARK: - Leaderboard Entry struct LeaderboardEntry: Identifiable, Codable { let id: String let position: Int let participantId: String let participantName: String let participantAvatarUrl: String? let progress: Double let progressPercentage: Double } // MARK: - Progress Submission struct ProgressSubmission: Encodable { let metric: ChallengeMetric let value: Double let activityDate: Date } // MARK: - Create Challenge Request struct CreateChallengeRequest: Encodable { let title: String let description: String let challengeType: ChallengeType let startDate: Date let endDate: Date let targetMetric: ChallengeMetric let targetValue: Double let rules: String? let clubId: String? } // MARK: - Update Challenge Request struct UpdateChallengeRequest: Encodable { var title: String? var description: String? var challengeType: ChallengeType? var startDate: Date? var endDate: Date? var targetMetric: ChallengeMetric? var targetValue: Double? var rules: String? var status: ChallengeStatus? } // MARK: - Challenge Filter struct ChallengeFilter: Encodable { var challengeType: ChallengeType? var status: ChallengeStatus? var participationStatus: ParticipationStatus? var clubId: String? var limit: Int var offset: Int init( challengeType: ChallengeType? = nil, status: ChallengeStatus? = nil, participationStatus: ParticipationStatus? = nil, clubId: String? = nil, limit: Int = 20, offset: Int = 0 ) { self.challengeType = challengeType self.status = status self.participationStatus = participationStatus self.clubId = clubId self.limit = limit self.offset = offset } } // MARK: - API Response Types struct ChallengeListResponse: Decodable { let challenges: [Challenge] let hasMore: Bool } struct ChallengeDetailResponse: Decodable { let challenge: Challenge let participants: [ChallengeParticipant] } struct CreateChallengeResponse: Decodable { let challenge: Challenge } struct UpdateChallengeResponse: Decodable { let challenge: Challenge } struct LeaderboardResponse: Decodable { let entries: [LeaderboardEntry] let userPosition: Int? let totalParticipants: Int } struct ParticipationResponse: Decodable { let success: Bool let challengeId: String let status: ParticipationStatus } struct ProgressResponse: Decodable { let success: Bool let challengeId: String let newProgress: Double let progressPercentage: Double }