import 'package:relationship_saver/features/local/local_models.dart'; import 'package:relationship_saver/features/share_intake/domain/signal_share_parser.dart'; import 'package:relationship_saver/features/share_intake/whatsapp_share_parser.dart'; class SharePayloadParser { const SharePayloadParser._(); static final RegExp _urlPattern = RegExp( r'(https?:\/\/[^\s]+|www\.[^\s]+)', caseSensitive: false, ); static SharedPayload parse({ required String rawText, required String sourceApp, required String platform, DateTime? createdAt, DateTime? receivedAt, }) { final DateTime now = DateTime.now(); final String normalizedSourceApp = _normalizeSourceApp(sourceApp); final String trimmed = rawText.trim(); final _ParsedSourceMetadata? sourceMetadata = _parseSourceMetadata( sourceApp: normalizedSourceApp, rawText: trimmed, ); final String candidateText = sourceMetadata?.messageText.trim() ?? trimmed; final RegExpMatch? urlMatch = _urlPattern.firstMatch(candidateText); final String? url = urlMatch == null ? null : _normalizeUrl(urlMatch.group(0)); final String cleanedText = url == null ? candidateText : candidateText.replaceFirst(urlMatch!.group(0)!, '').trim(); final SharedPayloadType payloadType; if (url != null && cleanedText.isNotEmpty) { payloadType = SharedPayloadType.textWithUrl; } else if (url != null) { payloadType = SharedPayloadType.url; } else { payloadType = SharedPayloadType.text; } return SharedPayload( sourceApp: normalizedSourceApp, payloadType: payloadType, rawText: cleanedText, url: url, createdAt: createdAt ?? now, receivedAt: receivedAt ?? now, platform: platform, sourceDisplayName: sourceMetadata?.sourceDisplayName, sourceUserId: sourceMetadata?.sourceUserId, sourceThreadId: sourceMetadata?.sourceThreadId, parsingHints: [ if (normalizedSourceApp != 'share_sheet') 'source_app_$normalizedSourceApp', if (url != null) 'contains_url', if (sourceMetadata?.sourceDisplayName case final String _) 'sender_detected', ], metadata: { if (url case final String value) 'primaryUrl': value, }, ); } static String detectSourceApp({ required String rawText, String? sourceAppHint, }) { final String normalizedHint = _normalizeSourceApp(sourceAppHint); if (normalizedHint != 'share_sheet') { return normalizedHint; } final String trimmed = rawText.trim(); if (_shouldUseWhatsAppParser(normalizedHint, trimmed)) { return 'whatsapp'; } return 'share_sheet'; } static bool _shouldUseWhatsAppParser(String sourceApp, String rawText) { if (sourceApp.contains('whatsapp')) { return true; } if (sourceApp != 'share_sheet') { return false; } if (rawText.contains(': ') && rawText.length < 4000) { return WhatsAppShareParser.looksLikeWhatsAppMessage(rawText); } return false; } static bool _shouldUseSignalParser(String sourceApp) { return sourceApp.contains('signal'); } static _ParsedSourceMetadata? _parseSourceMetadata({ required String sourceApp, required String rawText, }) { if (_shouldUseWhatsAppParser(sourceApp, rawText)) { final WhatsAppSharePayload payload = WhatsAppShareParser.parse(rawText); return _ParsedSourceMetadata( messageText: payload.messageText, sourceDisplayName: payload.sourceDisplayName, sourceUserId: payload.sourceUserId, sourceThreadId: payload.sourceThreadId, ); } if (_shouldUseSignalParser(sourceApp) && SignalShareParser.looksLikeSignalMessage(rawText)) { final SignalSharePayload payload = SignalShareParser.parse(rawText); return _ParsedSourceMetadata( messageText: payload.messageText, sourceDisplayName: payload.sourceDisplayName, sourceUserId: payload.sourceUserId, sourceThreadId: payload.sourceThreadId, ); } return null; } static String _normalizeSourceApp(String? raw) { final String value = raw?.trim().toLowerCase() ?? ''; if (value.isEmpty || value == 'generic' || value == 'text' || value == 'share sheet') { return 'share_sheet'; } if (value.contains('whatsapp')) { return 'whatsapp'; } if (value.contains('signal')) { return 'signal'; } if (value.contains('note')) { return 'notes'; } return value; } static String? _normalizeUrl(String? raw) { if (raw == null) { return null; } final String value = raw.trim(); if (value.isEmpty) { return null; } if (value.toLowerCase().startsWith('http://') || value.toLowerCase().startsWith('https://')) { return value; } return 'https://$value'; } } class _ParsedSourceMetadata { const _ParsedSourceMetadata({ required this.messageText, this.sourceDisplayName, this.sourceUserId, this.sourceThreadId, }); final String messageText; final String? sourceDisplayName; final String? sourceUserId; final String? sourceThreadId; }