import 'package:yumi/shared/business_logic/models/res/login_res.dart'; import 'package:yumi/shared/business_logic/models/res/sc_cp_rights_config_res.dart'; String? scCpRelationLevelTextFromCabin( SCCpCabinRes? cabin, { String? fallbackText, }) { if (cabin == null) { return _blankAsNull(fallbackText); } final currentValue = cabin.cpVal?.toDouble() ?? cabin.cpPairUserProfileCO?.cpValue; final computedLevel = _currentLevelFromDynamicConfigs( cabin.cpCabinConfigCO ?? const [], currentValue, ); final computedText = _formattedLevelText( level: computedLevel?.level, name: computedLevel?.levelName, ); if (computedText != null) { return computedText; } final currentConfig = _CpRelationLevelSource.fromDynamic( cabin.currentCpCabinConfigCO, ); final currentText = _formattedLevelText( level: currentConfig.level, name: currentConfig.levelName, ); if (currentText != null) { return currentText; } return _blankAsNull(cabin.cpPairUserProfileCO?.levelText) ?? _blankAsNull(fallbackText); } String? scCpRelationLevelTextFromRightsConfig( SCCpRightsConfigRes config, { String? fallbackText, }) { final currentValue = config.intimacyValue?.toDouble(); final computedLevel = _currentLevelFromRightsLevels( config.levels, currentValue, ); final computedText = _formattedLevelText( level: computedLevel?.level, name: computedLevel?.levelName, ); return computedText ?? _blankAsNull(fallbackText); } String scCpRelationLevelDisplayText(String? rawText) { final text = rawText?.trim() ?? ''; final level = scCpRelationLevelIndexOrNull(text); if (text.isEmpty) { return 'Lv.0'; } if (_isSimpleLoveLevelOneText(text, level)) { return 'Lv.1'; } final compactLevelPattern = RegExp( r'^(?:Lv\.?|Level)?\s*\d+$', caseSensitive: false, ); if (compactLevelPattern.hasMatch(text) && level != null) { return 'Lv.$level'; } return text; } int scCpRelationLevelIndex(String? levelText) { return scCpRelationLevelIndexOrNull(levelText) ?? 0; } int? scCpRelationLevelIndexOrNull(String? levelText) { final text = levelText?.trim() ?? ''; if (text.isEmpty) { return null; } final levelMatch = RegExp( r'(?:Lv\.?|Level|等级|级)\s*([0-5])|([0-5])\s*(?:级|Level)', caseSensitive: false, ).firstMatch(text); final fallbackMatch = RegExp(r'[0-5]').firstMatch(text); final rawLevel = levelMatch?.group(1) ?? levelMatch?.group(2) ?? fallbackMatch?.group(0); final level = int.tryParse(rawLevel ?? ''); return level?.clamp(0, 5).toInt(); } _CpRelationLevelSource? _currentLevelFromDynamicConfigs( List configs, double? currentValue, ) { final levels = configs.map(_CpRelationLevelSource.fromDynamic).where((level) { return level.requiredValue != null; }).toList() ..sort( (left, right) => left.requiredValue!.compareTo(right.requiredValue!), ); return _currentLevelFromSources(levels, currentValue); } _CpRelationLevelSource? _currentLevelFromRightsLevels( List levels, double? currentValue, ) { final sources = levels.map(_CpRelationLevelSource.fromRightsLevel).where((level) { return level.requiredValue != null; }).toList() ..sort( (left, right) => left.requiredValue!.compareTo(right.requiredValue!), ); return _currentLevelFromSources(sources, currentValue); } _CpRelationLevelSource? _currentLevelFromSources( List<_CpRelationLevelSource> levels, double? currentValue, ) { if (levels.isEmpty || currentValue == null) { return null; } _CpRelationLevelSource? currentLevel; for (final level in levels) { if ((level.requiredValue ?? 0) <= currentValue) { currentLevel = level; } } return currentLevel; } String? _formattedLevelText({int? level, String? name}) { final levelName = name?.trim() ?? ''; if (level == 1 && _isSimpleLoveName(levelName)) { return 'Lv.1'; } if (level != null && levelName.isNotEmpty) { final nameLevel = scCpRelationLevelIndexOrNull(levelName); if (nameLevel == level) { return scCpRelationLevelDisplayText(levelName); } return 'Lv.$level $levelName'; } if (level != null) { return 'Lv.$level'; } return _blankAsNull(levelName); } bool _isSimpleLoveLevelOneText(String text, int? level) { if (level != 1) { return false; } return RegExp( r'^(?:Lv\.?|Level)?\s*1\s+Simple\s+Love$', caseSensitive: false, ).hasMatch(text.trim()); } bool _isSimpleLoveName(String text) { return RegExp( r'^(?:Lv\.?|Level)?\s*1?\s*Simple\s+Love$', caseSensitive: false, ).hasMatch(text.trim()); } String? _blankAsNull(String? value) { final text = value?.trim() ?? ''; return text.isEmpty ? null : text; } class _CpRelationLevelSource { const _CpRelationLevelSource({ this.level, this.levelName, this.requiredValue, }); factory _CpRelationLevelSource.fromRightsLevel(SCCpRightsLevelRes level) { return _CpRelationLevelSource( level: level.level, levelName: level.levelName, requiredValue: level.requiredIntimacyValue, ); } factory _CpRelationLevelSource.fromDynamic(dynamic value) { final source = value is Map ? value : const {}; return _CpRelationLevelSource( level: _asInt( _firstValue(source, const ['level', 'cpLevel', 'cabinLevel', 'lv']), ), levelName: _asString( _firstValue(source, const [ 'levelName', 'name', 'title', 'cabinName', 'cpName', ]), ), requiredValue: _asInt( _firstValue(source, const [ 'requiredIntimacyValue', 'requiredCpValue', 'requiredCpVal', 'cpValue', 'cpVal', 'intimacyValue', ]), ), ); } final int? level; final String? levelName; final int? requiredValue; } dynamic _firstValue(Map source, List keys) { for (final key in keys) { if (source.containsKey(key) && source[key] != null) { return source[key]; } } return null; } String? _asString(dynamic value) { final text = value?.toString().trim(); return text == null || text.isEmpty ? null : text; } int? _asInt(dynamic value) { if (value is int) { return value; } if (value is num) { return value.toInt(); } return int.tryParse(value?.toString() ?? ''); }