class PublicParticipant { final String participantId; final String? memberId; final String name; final String? gender; final String? memberType; final num? average; final int handicap; final String? status; final String? paymentStatus; final String? comment; final bool isGuest; // 점수는 서버에서 number 또는 {score, handicap} 객체로 올 수 있음 // rawScores: 입력 점수(핸디캡 제외) // handicaps: 각 게임 핸디캡(없으면 0) final List rawScores; final List handicaps; PublicParticipant({ required this.participantId, required this.memberId, required this.name, required this.gender, required this.memberType, required this.average, required this.handicap, required this.status, required this.paymentStatus, required this.comment, required this.isGuest, required this.rawScores, required this.handicaps, }); factory PublicParticipant.fromJson(Map json, {int gameCount = 3}) { int parseInt(dynamic v, {int def = 0}) { if (v == null) return def; if (v is int) return v; return int.tryParse(v.toString()) ?? def; } num? parseNum(dynamic v) { if (v == null) return null; if (v is num) return v; return num.tryParse(v.toString()); } final List src = (json['scores'] is List) ? (json['scores'] as List) : const []; final List raw = List.filled(gameCount, null); final List hcs = List.filled(gameCount, 0); for (int i = 0; i < src.length && i < gameCount; i++) { final el = src[i]; if (el == null) { raw[i] = null; hcs[i] = 0; } else if (el is num) { raw[i] = el.toInt(); hcs[i] = 0; } else if (el is Map) { final score = el['score']; final hc = el['handicap']; raw[i] = (score is num) ? score.toInt() : int.tryParse(score?.toString() ?? ''); hcs[i] = (hc is num) ? hc.toInt() : (int.tryParse(hc?.toString() ?? '') ?? 0); } else { raw[i] = int.tryParse(el.toString()); hcs[i] = 0; } } final dynamic pidRaw = json['participantId']; final String pid = (pidRaw != null && pidRaw.toString().isNotEmpty) ? pidRaw.toString() : (json['id']?.toString() ?? ''); return PublicParticipant( participantId: pid, memberId: json['memberId']?.toString(), name: (json['name'] ?? '이름없음').toString(), gender: json['gender']?.toString(), memberType: json['memberType']?.toString(), average: parseNum(json['average']), handicap: parseInt(json['handicap'], def: 0), status: json['status']?.toString(), paymentStatus: json['paymentStatus']?.toString(), comment: json['comment']?.toString(), isGuest: json['isGuest'] == true, rawScores: raw, handicaps: hcs, ); } } enum ParticipantStatus { pending, confirmed, canceled, unknown } enum PaymentStatus { unpaid, paid, refunded, partial, unknown } enum MemberType { member, guest, staff, unknown } extension PublicParticipantEnums on PublicParticipant { ParticipantStatus get statusEnum { switch ((status ?? '').toLowerCase()) { case 'pending': return ParticipantStatus.pending; case 'confirmed': return ParticipantStatus.confirmed; case 'canceled': return ParticipantStatus.canceled; default: return ParticipantStatus.unknown; } } PaymentStatus get paymentEnum { switch ((paymentStatus ?? '').toLowerCase()) { case 'paid': return PaymentStatus.paid; case 'unpaid': return PaymentStatus.unpaid; case 'refunded': return PaymentStatus.refunded; case 'partial': return PaymentStatus.partial; default: return PaymentStatus.unknown; } } MemberType get memberTypeEnum { switch ((memberType ?? '').toLowerCase()) { case 'member': return MemberType.member; case 'guest': return MemberType.guest; case 'staff': return MemberType.staff; default: return MemberType.unknown; } } }