String scNormalizeCpRelationType(String? relationType) { final value = relationType?.trim().toUpperCase() ?? ""; switch (value) { case "BRO": case "BROS": case "BROTHER": case "BROTHERS": case "SWORN_BRO": case "SWORN_BROS": case "SWORN_BROTHER": case "SWORN_BROTHERS": return "BROTHER"; case "SIS": case "SISTER": case "SISTERS": return "SISTERS"; default: return "CP"; } } String scCpRelationBecomeLabel(String? relationType) { switch (scNormalizeCpRelationType(relationType)) { case "BROTHER": return "sworn brothers"; case "SISTERS": return "sisters"; default: return "a CP"; } } String scCpRelationPossessiveLabel(String? relationType) { switch (scNormalizeCpRelationType(relationType)) { case "BROTHER": return "brother"; case "SISTERS": return "sister"; default: return "CP"; } } String scCpRelationEntryLabel(String? relationType) { switch (scNormalizeCpRelationType(relationType)) { case "BROTHER": return "brother"; case "SISTERS": return "sister"; default: return "cp"; } } String scCpRelationDialogTitle(String? relationType) { switch (scNormalizeCpRelationType(relationType)) { case "BROTHER": return "Become sworn brothers"; case "SISTERS": return "Become sisters"; default: return "Become a couple"; } } String scCpRelationDisplayDays(String? days) { final text = days?.trim() ?? ""; final value = num.tryParse(text.replaceAll(",", "")); if (value == null) { return text.isEmpty ? "1" : text; } final displayValue = value + 1; if (displayValue % 1 == 0) { return displayValue.toInt().toString(); } return displayValue.toString(); } String scBuildCpRelationNoticeDedupKey({ required String? action, required String? groupId, required String? relationType, String? explicitKey, Iterable userIds = const [], Iterable userNames = const [], }) { final normalizedAction = action?.trim() ?? ""; final normalizedGroupId = groupId?.trim() ?? ""; final normalizedRelationType = scNormalizeCpRelationType(relationType); final normalizedExplicitKey = explicitKey?.trim() ?? ""; if (normalizedExplicitKey.isNotEmpty) { return [ "cp_notice", normalizedAction, normalizedGroupId, normalizedRelationType, normalizedExplicitKey, ].join("|"); } final ids = userIds .map((value) => value?.trim() ?? "") .where((value) => value.isNotEmpty) .toList() ..sort(); if (ids.isNotEmpty) { return [ "cp_notice", normalizedAction, normalizedGroupId, normalizedRelationType, ...ids, ].join("|"); } final names = userNames .map((value) => value?.trim() ?? "") .where((value) => value.isNotEmpty) .toList() ..sort(); if (names.isEmpty) { return ""; } return [ "cp_notice", normalizedAction, normalizedGroupId, normalizedRelationType, ...names, ].join("|"); } String scBuildCpRelationEstablishedNotice({ required String userName1, required String userName2, required String? relationType, }) { return "[System Notification] $userName1 and $userName2 have become " "${scCpRelationBecomeLabel(relationType)}."; } String scBuildCpRelationJoinNotice({ required String ownerName, required String joinedName, required String? relationType, }) { return "[System Notification] ${scBuildCpRelationEntryBroadcastText(ownerName: ownerName, joinedName: joinedName, relationType: relationType)}."; } String scBuildCpRelationEntryBroadcastText({ required String ownerName, required String joinedName, required String? relationType, }) { return "$ownerName's ${scCpRelationEntryLabel(relationType)} " "$joinedName has joined the party"; }