import 'package:relationship_saver/features/local/local_models.dart'; class ShareCaptureDraftSuggester { const ShareCaptureDraftSuggester._(); static final RegExp _birthdayPattern = RegExp( r'\bbirthday\b', caseSensitive: false, ); static final RegExp _anniversaryPattern = RegExp( r'\banniversary\b', caseSensitive: false, ); static final RegExp _giftPattern = RegExp( r'\b(gift|present|flowers|scarf|book for her|book for him)\b', caseSensitive: false, ); static final RegExp _placePattern = RegExp( r'\b(restaurant|cafe|coffee shop|bar|bistro|museum|park|hotel|beach|address|reservation)\b', caseSensitive: false, ); static final RegExp _activityPattern = RegExp( r'\b(concert|movie|hike|walk|trip|class|event|show|plan|weekend|tickets?)\b', caseSensitive: false, ); static final RegExp _negativePreferencePattern = RegExp( r"\b(hates?|dislikes?|allergic to|doesn't like|does not like|dont like)\b", caseSensitive: false, ); static final RegExp _positivePreferencePattern = RegExp( r'\b(loves?|likes?|favorite|prefers?|enjoys?)\b', caseSensitive: false, ); static final RegExp _isoDatePattern = RegExp( r'\b(\d{4})-(\d{1,2})-(\d{1,2})\b', ); static final RegExp _dotDatePattern = RegExp( r'\b(\d{1,2})\.(\d{1,2})\.(\d{2,4})\b', ); static final RegExp _monthNameDatePattern = RegExp( r'\b(january|february|march|april|may|june|july|august|september|october|november|december)\s+(\d{1,2})(?:,\s*(\d{4}))?\b', caseSensitive: false, ); static CapturedFactDraft suggestForPayload(SharedPayload payload) { final String text = payload.rawText.trim().isNotEmpty ? payload.rawText.trim() : (payload.url ?? '').trim(); final String normalized = text.toLowerCase(); final Uri? uri = payload.url == null ? null : Uri.tryParse(payload.url!); final String host = uri?.host.toLowerCase() ?? ''; final _SuggestedImportantDate? importantDate = _suggestImportantDate(text); if (importantDate != null) { return CapturedFactDraft( type: CapturedFactType.importantDate, text: importantDate.label, label: importantDate.label, dateValue: importantDate.date, isSensitive: false, needsReview: true, ); } if (_giftPattern.hasMatch(normalized)) { return CapturedFactDraft( type: CapturedFactType.giftIdea, text: text, label: 'Gift idea', isSensitive: false, needsReview: true, ); } if (_looksLikePlace(normalized, host)) { return CapturedFactDraft( type: CapturedFactType.placeIdea, text: text, label: 'Place idea', isSensitive: false, needsReview: true, ); } if (_looksLikeActivity(normalized, host)) { return CapturedFactDraft( type: CapturedFactType.activityIdea, text: text, label: 'Activity idea', isSensitive: false, needsReview: true, ); } if (_negativePreferencePattern.hasMatch(normalized)) { return CapturedFactDraft( type: CapturedFactType.dislike, text: text, label: 'Preference', isSensitive: normalized.contains('allergic'), needsReview: true, ); } if (_positivePreferencePattern.hasMatch(normalized)) { return CapturedFactDraft( type: CapturedFactType.like, text: text, label: 'Preference', isSensitive: false, needsReview: true, ); } return CapturedFactDraft( type: CapturedFactType.note, text: text, label: payload.url == null ? null : 'Shared link', isSensitive: false, needsReview: payload.url != null, ); } static bool _looksLikePlace(String normalized, String host) { if (_placePattern.hasMatch(normalized)) { return true; } return host.contains('maps.apple.com') || host.contains('google.com') && normalized.contains('maps') || host.contains('tripadvisor.') || host.contains('opentable.') || host.contains('thefork.'); } static bool _looksLikeActivity(String normalized, String host) { if (_activityPattern.hasMatch(normalized)) { return true; } return host.contains('eventbrite.') || host.contains('meetup.') || host.contains('ticketmaster.'); } static _SuggestedImportantDate? _suggestImportantDate(String text) { final DateTime? date = _parseDate(text); if (date == null) { return null; } final String normalized = text.toLowerCase(); if (_birthdayPattern.hasMatch(normalized)) { return _SuggestedImportantDate(date: date, label: 'Birthday'); } if (_anniversaryPattern.hasMatch(normalized)) { return _SuggestedImportantDate(date: date, label: 'Anniversary'); } return null; } static DateTime? _parseDate(String text) { final RegExpMatch? isoMatch = _isoDatePattern.firstMatch(text); if (isoMatch != null) { return _safeDate( int.parse(isoMatch.group(1)!), int.parse(isoMatch.group(2)!), int.parse(isoMatch.group(3)!), ); } final RegExpMatch? dotMatch = _dotDatePattern.firstMatch(text); if (dotMatch != null) { final int year = int.parse(dotMatch.group(3)!); return _safeDate( year < 100 ? 2000 + year : year, int.parse(dotMatch.group(2)!), int.parse(dotMatch.group(1)!), ); } final RegExpMatch? monthNameMatch = _monthNameDatePattern.firstMatch(text); if (monthNameMatch != null) { final int? month = _monthNameToInt(monthNameMatch.group(1)!); if (month == null) { return null; } final int day = int.parse(monthNameMatch.group(2)!); final int year = monthNameMatch.group(3) == null ? DateTime.now().year : int.parse(monthNameMatch.group(3)!); return _safeDate(year, month, day); } return null; } static DateTime? _safeDate(int year, int month, int day) { try { final DateTime value = DateTime(year, month, day); if (value.year != year || value.month != month || value.day != day) { return null; } return value; } catch (_) { return null; } } static int? _monthNameToInt(String input) { return switch (input.toLowerCase()) { 'january' => 1, 'february' => 2, 'march' => 3, 'april' => 4, 'may' => 5, 'june' => 6, 'july' => 7, 'august' => 8, 'september' => 9, 'october' => 10, 'november' => 11, 'december' => 12, _ => null, }; } } class _SuggestedImportantDate { const _SuggestedImportantDate({required this.date, required this.label}); final DateTime date; final String label; }