import 'package:p_tits_pas/models/card_assets.dart'; /// Statut d'une instance de carte (file d'attention) — contrat #194 / #173. enum CarteStatut { ouverte('ouverte'), refusee('refusee'), traitee('traitee'); final String apiValue; const CarteStatut(this.apiValue); static CarteStatut fromApi(String? raw) { switch (raw) { case 'refusee': return CarteStatut.refusee; case 'traitee': return CarteStatut.traitee; case 'ouverte': default: return CarteStatut.ouverte; } } } /// Mode de réponse attendu selon le type SYSTEM. enum CarteResponseMode { none('none'), ack('ack'), acceptRefuse('accept_refuse'); final String apiValue; const CarteResponseMode(this.apiValue); static CarteResponseMode fromApi(String? raw) { switch (raw) { case 'ack': return CarteResponseMode.ack; case 'accept_refuse': return CarteResponseMode.acceptRefuse; case 'none': default: return CarteResponseMode.none; } } } /// Bulle / carte de la file d'attention. class CarteBulle { final String id; final String typeCode; final String titre; final String? couleur; final String idPlacement; final String? idAbsence; final String operation; final CarteStatut statut; final Map payload; final DateTime? purgeAt; final String? creePar; final bool isCreator; final CarteResponseMode responseMode; final String? lastRefuseComment; final DateTime? creeLe; final DateTime? modifieLe; const CarteBulle({ required this.id, required this.typeCode, required this.titre, this.couleur, required this.idPlacement, this.idAbsence, this.operation = 'create', required this.statut, this.payload = const {}, this.purgeAt, this.creePar, this.isCreator = false, this.responseMode = CarteResponseMode.none, this.lastRefuseComment, this.creeLe, this.modifieLe, }); String? get dateDebut => payload['date_debut']?.toString(); String? get dateFin => payload['date_fin']?.toString(); String? get motif => payload['motif']?.toString(); /// Libellé UI (sémantique produit) — pas le titre brut API. String get titreAffiche { switch (typeCode) { case 'conge_am': return 'Demande de congés'; case 'arret_maladie_am': return 'Arrêt maladie'; case 'absence_enfant': case 'absence_enfant_modif': return 'Notification d’absence'; default: return titre; } } /// Asset horizontal pastel (palette `assets/cards/` uniquement). String get backgroundAsset { final key = (couleur ?? '').trim().toLowerCase(); switch (key) { case 'red': return CardColorHorizontal.red.path; case 'pink': return CardColorHorizontal.pink.path; case 'peach': return CardColorHorizontal.peach.path; case 'lime': return CardColorHorizontal.lime.path; case 'lavender': return CardColorHorizontal.lavender.path; case 'green': return CardColorHorizontal.green.path; case 'blue': return CardColorHorizontal.blue.path; default: return CardColorHorizontal.peach.path; } } /// Le destinataire peut répondre (pas le créateur, carte ouverte). bool get peutRepondre => !isCreator && statut == CarteStatut.ouverte && responseMode != CarteResponseMode.none; factory CarteBulle.fromJson(Map json) { final rawPayload = json['payload']; return CarteBulle( id: (json['id'] ?? '').toString(), typeCode: (json['type_code'] ?? '').toString(), titre: (json['titre'] ?? json['type_code'] ?? 'Carte').toString(), couleur: json['couleur']?.toString(), idPlacement: (json['id_placement'] ?? '').toString(), idAbsence: json['id_absence']?.toString(), operation: (json['operation'] ?? 'create').toString(), statut: CarteStatut.fromApi(json['statut']?.toString()), payload: rawPayload is Map ? Map.from(rawPayload) : const {}, purgeAt: _parseDate(json['purge_at']), creePar: json['cree_par']?.toString(), isCreator: json['is_creator'] == true, responseMode: CarteResponseMode.fromApi(json['response_mode']?.toString()), lastRefuseComment: json['last_refuse_comment']?.toString(), creeLe: _parseDate(json['cree_le']), modifieLe: _parseDate(json['modifie_le']), ); } static DateTime? _parseDate(dynamic v) { if (v == null) return null; return DateTime.tryParse(v.toString()); } }